Three.jsことはじめ

こんにちわ、てぬ太:fish:です。
この記事では「Three.jsことはじめ」と銘打って立方体を表示するまでの過程を示します。
<img width="300" alt="threejs3.gif" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1116978/f25b39e6-d52d-1605-0eae-c80c515d5611.gif">

細かいパラメータ等には触れずThree.jsを扱うにあたって必要な処理を中心にまとめます。
同じような初心者の方が3D空間にオブジェクトを配置するイメージをつかめれば幸いです。

また、アップデート等に対応できるようドキュメントへのリンクを都度貼ります。

【目次】
[3Dコンテンツを作りたい！](#3dコンテンツを作りたい)※ポエム
[Three.jsとは](#threejsとは)
[Getting Started](#getting-started)
　[①HTMLファイルを用意する](#htmlファイルを用意する)
　[②Three.jsを用意する](#threejsを用意する)
　[③scene、camera、rendererを作成する](#scenecamerarendererを作成する)
　[④立方体を作成する](#立方体を作成する)
　[⑤立方体を表示する](#立方体を表示する)
　[⑥立方体を回転させる](#立方体を回転させる)
[まとめ](#まとめ)
[おまけ](#おまけ)

【github】
~~https://github.com/tenugui-taro/threejs_sample_public~~

##3Dコンテンツを作りたい！
これまで [Vue](https://jp.vuejs.org/index.html) × [Vuetify](https://vuetifyjs.com/ja/) でアプリを作成してきました。
この構成でもマテリアルデザインに準拠した基本的なアプリは出来ますが、
<strong>やっぱりログイン画面くらいは動きをつけてユーザーを惹きつけたい！！</strong>

というわけで javascriptを用いて3Dコンテンツを扱えるThree.jsを触ってみることにしました。
##Three.jsとは
[three.js](https://threejs.org/)
HTML5で3Dコンテンツを制作できる javascriptライブラリ
サイトを訪れると様々な作品が紹介されていました。
<img width="600" alt="スクリーンショット 2021-04-02 011741.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1116978/12a44d3e-cf6a-7722-44be-cd9c209033df.png">
[crossy-road](https://poki.com/en/g/crossy-road)
※昔ハマったゲームが紹介されていたのもライブラリ選定のポイント
<img width="600" alt="スクリーンショット 2021-04-02 015052.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1116978/f243f78b-18fb-2024-767d-d3ca6fbb60bb.png">

##Getting Started
####①HTMLファイルを用意する
[Before we start](https://threejs.org/docs/index.html#manual/en/introduction/Creating-a-scene)を参照し、HTMLファイルを作成してコピペします。

```html:index.html
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>My first three.js app</title>
		<style>
			body { margin: 0; }
		</style>
	</head>
	<body>
		<script src="js/three.js"></script>
		<script>
			// ここにjavascript処理を記述する
		</script>
	</body>
</html>
```
####②Three.jsを用意する
[github](https://github.com/mrdoob/three.js/)を参照しthree.jsファイルをダウンロードしてきます。
※CDNで用意する方法もあります。お好みで。
<img width="600" alt="スクリーンショット 2021-04-02 020751.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1116978/6efc634c-0657-e128-8c48-4182f19a8eb3.png">
この時点でのディレクトリ構成は以下の通りです。

```
C:.
│  index.html
│
└─js
        three.js
```
####③scene、camera、rendererを作成する
Three.jsを扱うための３種の神器です。
細かいパラメータはさておき、用語のイメージは下記の通り。

* scene：3D空間
* camera：カメラ、いくつかあるので用途に応じて選択する。今回は人間の見え方に近い[PerspectiveCamera](https://threejs.org/docs/index.html?q=camera#api/en/cameras/PerspectiveCamera)を選択
* renderer：WebGLを扱うためのレンダラー

```javascript
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );

const renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
```

#### ④立方体を作成する
オブジェクト作成にあたっては、形状指定とマテリアルの２点が必要です。

まずgeometry（形状）を指定します。今回は[BoxGeometry](https://threejs.org/docs/index.html?q=Box#api/en/geometries/BoxGeometry)を参照し立方体を指定します。
次にmaterialを用意します。[MeshBasicMaterial](https://threejs.org/docs/index.html?q=mesh#api/en/materials/MeshBasicMaterial)ではパラメータをいじって仕上がりを確認することもできます。

```javascript
const geometry = new THREE.BoxGeometry();
const material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );
const cube = new THREE.Mesh( geometry, material );
scene.add( cube );

// 表示の都合上、カメラの位置を設定しておく
camera.position.z = 5;
```
#### ⑤立方体を表示する
ここまでの手順を踏んでもまだ何も表示されません。
実はまだ何もレンダリングしていないからです。

```javascript
renderer.render( scene, camera ); // レンダリング
```
この時点でindex.htmlを開くと以下の画像のように表示されます。
<img width="300" alt="スクリーンショット 2021-04-02 025901.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1116978/83f70ad2-08b0-7739-ee27-3a6dff451b1f.png">

#### ⑥立方体を回転させる
現在は立方体の一面を映しているだけなので正方形のように見えます。
そこで、アニメーション処理を加えて立方体であることを確認します。
また、レンダリング処理も加えて更新します。

```javascript
function animate() {
    requestAnimationFrame(animate);
    cube.rotation.x += 0.01;
    cube.rotation.y += 0.01;
    renderer.render(scene, camera); // レンダリング
}
animate();
```
動きがついて立方体であることが確認できました！
<img width="300" alt="threejs2.gif" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1116978/eab31d90-d286-075d-7b23-e858e3844fe3.gif">
すべての処理を記述したindex.htmlは以下の通りです。

```html:index.html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>My first three.js app</title>
    <style>
      body {
        margin: 0;
      }
    </style>
  </head>
  <body>
    <script src="js/three.js"></script>
    <script>
      // ③scene、camera、rendererを用意する
      const scene = new THREE.Scene();
      const camera = new THREE.PerspectiveCamera(
        75,
        window.innerWidth / window.innerHeight,
        0.1,
        1000
      );

      const renderer = new THREE.WebGLRenderer();
      renderer.setSize(window.innerWidth, window.innerHeight);
      document.body.appendChild(renderer.domElement);

      // ④立方体を用意する
      const geometry = new THREE.BoxGeometry();
      const material = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
      const cube = new THREE.Mesh(geometry, material);
      scene.add(cube);

      camera.position.z = 5;

      // ⑤立方体を表示する
      // ⑥立方体を回転させる
      function animate() {
        requestAnimationFrame(animate);
        cube.rotation.x += 0.01;
        cube.rotation.y += 0.01;
        renderer.render(scene, camera); // レンダリング
      }
      animate();
    </script>
  </body>
</html>
```
##まとめ
ひとまず立方体を表示することができました！
やはりライブラリを利用すると手軽に実装できますね。学習コストはかかりますが...
インタラクティブなアプリを目指して引き続き勉強していきます:cherry_blossom::cherry_blossom:

##おまけ
公式ドキュメントでは様々なパラメータをいじりながら仕上がりを確認することができます。
試しに[BoxGeometry](https://threejs.org/docs/index.html?q=Box#api/en/geometries/BoxGeometry)にワイヤーフレーム表示の設定を加えます。

```javascript
const material = new THREE.MeshBasicMaterial({
    color: 0x00ff00,
    wireframe: true, // ワイヤーフレーム表示
});
```
<img width="300" alt="threejs3.gif" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1116978/f25b39e6-d52d-1605-0eae-c80c515d5611.gif">