Three.js勉強3: 3Dオブジェクトの描画

# はじめに
以前、[React Three Fiber(R3F)に関する記事](https://qiita.com/skm_bnn/items/9bdca6e2965fe8fa61e5)を投稿しました。ReactではThree.jsを容易に扱えるとの噂で、触ってみましたが、そもそもThree.jsでできることが何なの分からず、環境構築止まりになってしまいました。そこで、本記事ではThree.jsを基礎から学びつつ、備忘録として記事にまとめてみたいと思います。

- [Three.js勉強1: 環境構築](https://qiita.com/skm_bnn/private/fe4c17ac65ce5c4a89db)
- [Three.js勉強1.5: 環境構築(ローカル編)](https://qiita.com/skm_bnn/private/4a9a739ec08a41f2588e)
- [Three.js勉強2: シーンの主要要素](https://qiita.com/skm_bnn/private/32f21e39ed40668041e9)
- [Three.js勉強3: 3Dオブジェクトの描画](https://qiita.com/skm_bnn/private/e0611cfd717b96f7ff98)
- [Three.js勉強4: アニメーションと再レンダリング](https://qiita.com/skm_bnn/private/9bd86ab51a829efc43ef)

# 前回の記事

https://qiita.com/skm_bnn/items/32f21e39ed40668041e9

# 3Dオブジェクト
立体的なオブジェクトとして立方体を作成していきます。描画したいオブジェクトのメッシュを生成するにあたり、ジオメトリとマテリアルの情報が必要です。従って、次の工程で実装していきます。

1. ジオメトリの生成
1. マテリアルの生成
1. メッシュの生成
1. シーンの追加

## ジオメトリの生成
ジオメトリオブジェクトは、形状(頂点と面)の情報をもっています。次のコードで直方体型ジオメトリオブジェクトのインスタンスを生成できます。

```js
const ジオメトリ = new THREE.BoxGeometry( 横幅, 高さ, 深さ );
```

|引数|内容|値の例|
|---|---|---|
|横幅|直方体の横幅|```1```|
|高さ|直方体の高さ|```1```|
|深さ|直方体の深さ|```1```|

## マテリアルの生成
マテリアルオブジェクトは、材質の情報をもっています。

### マテリアルの種類
マテリアルには次のような複数種類があります。

- [```MeshBasicMaterial```](https://threejs.org/docs/#api/en/materials/MeshBasicMaterial)
- [```MeshLambertMaterial```](https://threejs.org/docs/#api/en/materials/MeshLambertMaterial)
- [```MeshPhongMaterial```](https://threejs.org/docs/#api/en/materials/MeshPhongMaterial)
- [```MeshStandardMaterial```](https://threejs.org/docs/#api/en/materials/MeshStandardMaterial)
- [```MeshToonMaterial```](https://threejs.org/docs/#api/en/materials/MeshToonMaterial)

次のページで各マテリアルの簡単な比較をしています。

https://qiita.com/skm_bnn/items/4e1b1bbc9de93ec04f8c

### プロパティオブジェクト
マテリアルオブジェクトのインスタンスを生成する際に、プロパティオブジェクトを渡す必要があります。これは、マテリアルのプロパティ(色、不透明度などの設定項目)をもつオブジェクトです。プロパティには[全マテリアル共通](https://threejs.org/docs/#api/en/materials/MeshBasicMaterial)のものと各マテリアル独自のものがあります。各マテリアル独自のプロパティは、「[マテリアルの種類](#マテリアルの種類)」に挙げたリンクから確認できます。

今回の記事では```MeshBasicMaterial```に指定した色で塗りつぶしたマテリアルを作成していきます。```MeshBasicMaterial```は、光の影響を受けずに描画されることが特徴です。次のコードで```MeshBasicMaterial```オブジェクトのインスタンスを生成できます。「色コード」は16進数の6桁で表します。
```js
const マテリアル = new THREE.MeshBasicMaterial( { color: 色コード } );
```

## メッシュの生成
生成したジオメトリとマテリアルを用いて、次のコードでメッシュオブジェクトのインスタンスを生成できます。メッシュオブジェクトを生成することで、描画したいオブジェクトを定義できます。
```js
const メッシュ = new THREE.Mesh( ジオメトリ, マテリアル );
```

## シーンへの追加
主要な構成要素の1つであるシーンオブジェクトを用いて、次のコードで描画オブジェクトをシーンへ反映することができます。

```js: 
シーン.add( メッシュ );
```

## 例
緑色の立方体をシーン上の原点```(0, 0, 0)```に追加するプログラムを次に示します。
```js
const geometry = new THREE.BoxGeometry( 1, 1, 1 );
const material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );
const cube = new THREE.Mesh( geometry, material );
scene.add( cube );
```

# 描画処理
3Dオブジェクトを描画するために次の手続きをします。

1. カメラと立方体が同じ座標にあるため、カメラを移動させる
1. シーンにレンダリングする

## カメラの移動
カメラを移動するには、カメラオブジェクトの```position```プロパティを変更する必要があります。このプロパティには、さらに```x```、```y```、```z```プロパティがあります。これらの値を変更することで、カメラオブジェクトを移動できます。

```js
カメラ.position.x = x座標
カメラ.position.y = y座標
カメラ.position.z = z座標
```

## シーンのレンダリング
HTMLでシーンを描画させるためには、レンダリングの手続きが必要です。次に構文を示します。

```js
レンダラー.render(シーン, カメラ);
```

# ソースコード
次に今回までの内容をまとめたソースコードを示します。

```js: main.js
import * as THREE from 'three';

/* シーンの実装 */
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);           // HTMLへの追加

/* 描画オブジェクトの実装 */
const geometry = new THREE.BoxGeometry(1, 1, 1);                    // ジオメトリの生成
const material = new THREE.MeshBasicMaterial({ color: 0x00ff00 });  // マテリアルの生成
const cube = new THREE.Mesh(geometry, material);                    // メッシュの生成
scene.add(cube);                                                    // シーンへの追加

/* カメラの移動 */
camera.position.z = 5;

/* シーンのレンダリング */
renderer.render(scene, camera);
```

# 動作結果
これで、緑色の立方体があるシーンを描画することができました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2844961/d7f79144-abcd-48af-8be3-617efdbd4c4a.png)

# 次回の記事

https://qiita.com/skm_bnn/items/9bd86ab51a829efc43ef

# 参考
- シーンの作成

https://threejs.org/docs/#manual/en/introduction/Creating-a-scene