Three.jsことはじめ ~GUIでパラメータ調整~

こんにちわ、てぬ太:fish:です。
この記事は[前回](https://qiita.com/tenugui_taro/items/0d6625b2d6f1963b89ab)の続きとして、球体の表示およびGUIによるパラメータ調整を行うまでの過程を示します。
<img width="300" alt="threejs_gui.gif" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1116978/9e0bb4c3-0bb2-0431-7044-cff4324f743f.gif">
【目次】
[球体を表示する](#球体を表示する)
　[①HTMLファイル作成](#htmlファイル作成)
　[②Three.jsを用意](#threejsを用意)
　[③scene、camera、renderer作成](#scenecamerarenderer作成)
　[④球体を作成](#球体を作成)
　[⑤光源を追加](#光源を追加)
[GUIでパラメータ調整](#guiでパラメータ調整)
　[⑥GUIを用意](#guiを用意)
　[⑦パラメータ設定](#パラメータ設定)
[まとめ](#まとめ)

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

【前回記事】
[Three.jsことはじめ](https://qiita.com/tenugui_taro/items/0d6625b2d6f1963b89ab)

## 球体を表示する
※前回記事とはディレクトリ構成が異なっています。

```
C:.
    index.html
    main.js
```
#### ①htmlファイル作成
公式ドキュメント：[Before we start](https://threejs.org/docs/index.html#manual/en/introduction/Creating-a-scene)

```html:index.html
<!DOCTYPE html>
<html>
  <head>
    <title>My first three.js app</title>
    <style>
      body {
        margin: 0;
      }
    </style>
  </head>
  <body>
    <script src="./main.js" type="module"></script>
  </body>
</html>
```
#### ②Three.jsを用意
[前回](https://qiita.com/tenugui_taro/items/0d6625b2d6f1963b89ab#threejs%E3%82%92%E7%94%A8%E6%84%8F%E3%81%99%E3%82%8B)はローカルに用意しましたが、せっかくなのでimport文からCDNで読み込みます。

```javascript:main.js
import * as THREE from "https://unpkg.com/three@0.127.0/build/three.module.js";
```

#### ③scene、camera、renderer作成
詳細は[前回](https://qiita.com/tenugui_taro/items/0d6625b2d6f1963b89ab#scenecamerarenderer%E3%82%92%E4%BD%9C%E6%88%90%E3%81%99%E3%82%8B)を参照ください。

差分としては、カメラのマウス制御を可能にする`OrbitControls`をCDNで追加しています。
公式ドキュメント：[OrbitControls](https://threejs.org/docs/index.html?q=contro#examples/en/controls/OrbitControls)

```javascript:main.js
const scene = new THREE.Scene();

const camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.set(75, 20, 0);

const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

// cameraをマウス操作で制御
import { OrbitControls } from "https://unpkg.com/three@0.127.0/examples/jsm/controls/OrbitControls.js";
const controls = new OrbitControls(camera, renderer.domElement);
```

#### ④球体を作成
`THREE.SphereGeometry`で球体を指定します。
また、`renderer.render(scene, camera);`でレンダリング処理を行います。

公式ドキュメント：[SphereGeometry](https://threejs.org/docs/index.html?q=SphereGeometry#api/en/geometries/SphereGeometry)

```javascript:main.js
const Sphere = new THREE.Mesh(
  new THREE.SphereGeometry(5, 32, 32),
  new THREE.MeshStandardMaterial({ color: 0xffffff })
);
Sphere.position.set(0, 5, 0);
scene.add(Sphere);

// フレーム毎の処理
const animate = () => {
  requestAnimationFrame(animate);
  renderer.render(scene, camera);
};
animate();
```

#### ⑤光源を追加
しかし、現時点では何も表示されません。なぜでしょう。
<img width="300" alt="スクリーンショット 2021-04-08 041636.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1116978/2a67ec94-2f7b-6e39-9071-835cdf8294fe.png">

実は3D空間に光源がないからです。
ということで、空側の色と地面側の色を設定できる`HemisphereLight`を追加します。

公式ドキュメント：[HemisphereLight](https://threejs.org/docs/index.html?q=He#api/en/lights/HemisphereLight)

```javascript:main.js
const hemisphereLight = new THREE.HemisphereLight(
  /* sky color = */ 0x51a8dd,
  /* ground color = */ 0xe83015
);
scene.add(hemisphereLight);
```
表示されるようになりました！
また、クリックしながらぐりぐりすると様々な角度から見られます。
<img width="300" alt="スクリーンショット 2021-04-08 042824.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1116978/d074cd28-d5db-f7b5-e6db-ad709e39a2d0.png">

ここまでの`main.js`は以下の通り。

```javascript:main.js
import * as THREE from "https://unpkg.com/three@0.127.0/build/three.module.js";
import { OrbitControls } from "https://unpkg.com/three@0.127.0/examples/jsm/controls/OrbitControls.js";

// scene、camera、rendererを用意
const scene = new THREE.Scene();

const camera = new THREE.PerspectiveCamera(
  60,
  window.innerWidth / window.innerHeight,
  1,
  1000
);
camera.position.set(75, 20, 0);

const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

// cameraをマウス操作で制御
const controls = new OrbitControls(camera, renderer.domElement);

// 球体を配置
const Sphere = new THREE.Mesh(
  new THREE.SphereGeometry(5, 32, 32),
  new THREE.MeshStandardMaterial({ color: 0xffffff })
);
Sphere.position.set(0, 5, 0);
scene.add(Sphere);

// sky color と ground color を設定
const hemisphereLight = new THREE.HemisphereLight(
  /* sky color = */ 0x51a8dd,
  /* ground color = */ 0xe83015
);
scene.add(hemisphereLight);

// フレーム毎の処理
const animate = () => {
  requestAnimationFrame(animate);
  renderer.render(scene, camera);
};
animate();
```

## GUIでパラメータ調整
それでは、光源の色をGUIで調整できるようにします。

#### ⑥GUIを用意
以下をコピペするだけなので説明は省略します。
※見づらいですが画面右上に「Close Controls」と出ます。

```javascript:main.js
import { GUI } from "https://unpkg.com/three@0.127.0/examples/jsm/libs/dat.gui.module.js";

const gui = new GUI({ width: 300 });
gui.open();
```

#### ⑦パラメータ設定
GUIで調整するパラメータを設定します。
[HemisphereLight](https://threejs.org/docs/index.html?q=He#api/en/lights/HemisphereLight)の`Properties`を参照したところ、`hemisphereLight.color`と`.groundColor`でそれぞれ設定するようです。

```javascript:main.js
let param = {
  "sky color": hemisphereLight.color.getHex(),
  "ground color": hemisphereLight.groundColor.getHex(),
};

gui.addColor(param, "sky color").onChange((val) => {
  hemisphereLight.color.setHex(val);
});

gui.addColor(param, "ground color").onChange((val) => {
  hemisphereLight.groundColor.setHex(val);
});
```
できました！！:cherry_blossom:
<img width="300" alt="threejs_gui.gif" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1116978/9e0bb4c3-0bb2-0431-7044-cff4324f743f.gif">

## まとめ
GUI操作によるパラメータ調整のおかげで仕上がりの確認が格段に速くなりますね:cherry_blossom:
ゆくゆくは好きな生き物を動かしたりしたいですが、いつになるやら...