🤖

React+TypeScriptなWebアプリで、three.jsの3D表示の最初の一歩。"React Three Fiber"なしで。

2023/12/16に公開

Abstract

React+Typescriptでthree.jsを試してみたかったというモチベーションで。
最初の一歩として、立方体を表示させてみた。
Reactには、"React Three Fiber"って素晴らしかライブラリがあるとですけど、今回はあえて使わず。
環境構築~3D表示まで。

結論

今回の成果物はココ↓
https://github.com/aaaa1597/react-threejs-1ststep

前提

手順

1.プロジェクト生成 -> VSCodeで開く

めんどいから、プロジェクト雛形をgithubから持ってくる。React+TypeScriptのプロジェクト雛形をgithubに置いとく話。
で、下記コマンドでフォルダ名とか整備する。

フォルダリネームとか
$ ProjectName=react-threejs-1ststep
$ cd ~
$ git clone https://github.com/aaaa1597/React-Ts-Template.git
$ rm -rf React-Ts-Template/.git
$ rm -rf ${ProjectName}
$ mv React-Ts-Template ${ProjectName}

2.生成したプロジェクトの場所でthree.jsをインストール

$ cd プロジェクトのフォルダ
$ npm install
$ npm install --save three
$ npm install @types/three

App.tsxを作っていく

1.描画領域(<canvas />)を生成

App.tsx <canvas />生成
-import React from 'react';
+import React, { useEffect, useRef } from 'react';
 import './App.css';
+import * as THREE from 'three';

+// サイズを指定
+const DISPLAY_WIDTH  = 960;
+const DISPLAY_HEIGHT = 540;

-function App() {
+const App = () => {
+  const canvasRef   = useRef<HTMLCanvasElement>(null);

+  useEffect(() => {
+        //レンダラーを作成
+        const renderer: THREE.WebGLRenderer = new THREE.WebGLRenderer({
+          canvas: canvasRef.current??undefined,
+      });

+      renderer.setPixelRatio(window.devicePixelRatio);
+      renderer.setSize(DISPLAY_WIDTH, DISPLAY_HEIGHT);
+    }, [])

   return (
     <div className="App">
+        <canvas width={DISPLAY_WIDTH} height={DISPLAY_HEIGHT} ref={canvasRef} />
       hello world!!
     </div>
   );
}

export default App;


まだ空っぽ。なんとなくcanvasが配置されているのが見える。

2.シーン、カメラ、モデル(今回はBOX)を生成

シーン、カメラ、モデルは、three.js独特だ。要はこれらを毎フレーム変更すればいいんだな。
ふ~ん。

App.tsx シーン、カメラ、モデルを生成
~ 略 ~
// サイズを指定
const DISPLAY_WIDTH  = 960;
const DISPLAY_HEIGHT = 540;

const App = () => {
~ 略 ~
  useEffect(() => {
~ 略 ~
      renderer.setPixelRatio(window.devicePixelRatio);
      renderer.setSize(DISPLAY_WIDTH, DISPLAY_HEIGHT);

+     // シーンを作成
+     const scene = new THREE.Scene();

+     // カメラを作成
+     const camera = new THREE.PerspectiveCamera(45, DISPLAY_WIDTH / DISPLAY_HEIGHT);
+     camera.position.set(0, 0, +1000);

+     // 箱を作成
+     const geometry = new THREE.BoxGeometry(400, 400, 400);
+     const material = new THREE.MeshNormalMaterial();
+     const box = new THREE.Mesh(geometry, material);
+     scene.add(box);
    }, [])
~ 略 ~


まだ空っぽ。そりゃそうだ。定義はしたけど、描画はしてないもんね。

3.描画を生成

描画関数を作って、呼ぶ。

App.tsx 描画
~ 略 ~
const App = () => {
~ 略 ~
     const geometry = new THREE.BoxGeometry(400, 400, 400);
     const material = new THREE.MeshNormalMaterial();
     const box = new THREE.Mesh(geometry, material);
     scene.add(box);
 
+    const tick = () => {
+      box.rotation.y += 0.01
+      renderer.render(scene, camera)
+      requestAnimationFrame(tick);
+    }
+
+    /* 初回起動 */
+    tick()

    }, [])
~ 略 ~


出来た!!

意外に簡単。
WebGLって聞いてたから、もっと初期化が複雑かと思ってた。

Discussion