WebGLでミラーボールを作るハンズオン(react-three-fiber + drei + TypeScript)

WebGLでミラーボールを作ってみます。ハンズオン的に全ての手順を説明します。
ツールとしてはreact-three-fiber + drei + TypeScript + create-react-appを使います。

## 本記事の想定読者
Web開発に詳しいが、3Dは詳しくない人向けです。

## 今回作成するもの

[動くデモはこちら](https://kabosu3d.github.io/cra-ts-r3f-drei-starter-demo/)

![gamen_test1.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/198108/0c44fcc7-f6f2-6bf8-f14d-3e9b7c89d365.gif)

## 解説
### 1. ３Dモデル作り

まずBlender(ここではバージョン2.92.0)を起動します。

立方体をクリックしてキーボードの「X(エックス)」を押下し、画面に表示された「削除」を押す。

![スクリーンショット 2021-11-26 21.53.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/198108/e1dea71d-274d-3a62-f973-bee72c9ecd63.png)

Command + A (Windowsでは Ctrl + A) を押して「メッシュ」→「UV球」 

![スクリーンショット 2021-11-26 21.54.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/198108/62b1831a-8a68-f773-3b78-5dabff408bfb.png)

球ができたら球をクリックし、以下の1→2をクリック

![スクリーンショット 2021-11-26 21.50.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/198108/b0c62053-f1c3-fdbb-2568-db712172b6f8.png)

「メタリック」と「粗さ」を図のとおり設定する。

- メタリック: 0.926
- 粗さ: 0.074

![スクリーンショット 2021-11-26 21.50.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/198108/f9d27cc8-2971-4982-fff5-5906a77c522f.png)

モデルを.glb形式に変換する。「ファイル」→「エクスポート」→「glTF 2.0(.glb/.gltf)」と選択

![スクリーンショット 2021-11-26 21.50.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/198108/5c0d9d07-ab04-febe-a83f-8655a9456af0.png)

名前を「ball.glb」と設定して、あとは何も変えずに「glTF2.0をエクスポート」を押す。

![スクリーンショット 2021-11-26 21.51.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/198108/84d6e880-8a49-0d32-b358-21eb1f9da975.png)

モデルはこれで完成となります。

### 2. 実装 

ここから実装をしていきます。まずライブラリのインストールをします。

```sh
yarn create react-app my-app --template typescript  
yarn add three @react-three/fiber @types/three 
yarn add @react-three/drei

# そして開発サーバーの起動
cd my-app
yarn
yarn start
```

まず、3Dモデルを配置しておきます。`src`ディレクトリ直下に、先ほど作った`ball.glb`を入れます。

それではコードを修正していきます。

`src/global.d.ts`ファイルを作成し、以下を書き込みます。
これにより、先ほど作った.glbファイルがTypeScriptから読み込めるようになります。

```ts
declare module "*.glb";
```


`src/index.css`の先頭に以下のコードを追加します。
これはレイアウト調整のためです。

```css
html,
body,
#root,
#root > div {
  height: 100%;
}
```

`src/App.tsx`を以下のコードに入れ替えます。
これにより、3Dモデルが読み込まれ、画面に表示されます。

```tsx
import "./App.css";
import React, { Suspense } from "react";
import { Canvas, useFrame } from "@react-three/fiber";
import { useGLTF, Environment, OrbitControls } from "@react-three/drei";
import modelPath from "./ball.glb";
import { GLTF } from "three/examples/jsm/loaders/GLTFLoader";

function Model() {
  const gltf = useGLTF(modelPath) as unknown as GLTF;
  useFrame(() => (gltf.scene.rotation.y += 0.002));
  return <primitive object={gltf.scene} />;
}
function App() {
  return (
    <div className="App">
      <Canvas>
        <OrbitControls />
        <color attach="background" args={[0x333353]} />
        <ambientLight />
        <pointLight position={[10, 10, 10]} />
        <Suspense fallback={null}>
          <Environment preset="studio" />
          <Model />
        </Suspense>
      </Canvas>
    </div>
  );
}

export default App;
```

以上です。

## ソースコード

今回作ったものは以下にあります。うまく動かない場合参考にしてください。

https://github.com/kabosu3d/cra-ts-r3f-drei-starter


## 確認環境
- Node.js v14.17.1
- Blender 2.92.0
- MacBook Pro (16-inch 2019)
- macOS Monterey 12.0.1