three.js の公式サンプルを p5.js Web Editor上で扱うための下準備（独立したキャンバスでシンプルな描画から）

この記事は、p5.js Web　Editor上で、three.js による描画を行ってみる、というものです。
ちょっと前に、PixiJS　について以下のような記事を書いたのですが、それと同じようなことをやります。

●PixiJS でパーティクルを描画して p5.js で扱うための下準備（まずは独立したキャンバスでシンプルな描画から） - Qiita
　https://qiita.com/youtoy/items/238a3a083eaf8cd4abf7

## 今回行うことの概要
### 参照する公式サンプル
それでは早速、本編へと入っていきます。
●The First Step | Babylon.js Playground
　https://playground.babylonjs.com/#2KRNG9
まず、three.js で実装する内容は、以下の公式サンプルです。

●Creating a scene – three.js docs
　https://threejs.org/docs/#manual/en/introduction/Creating-a-scene

最終的に用いるおおよその内容は、上記のページ内の「The result」に書かれた内容です。
![The result](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/59b0b9e0-c0a8-dd50-811e-2fab9d25fae5.png)

### 公式サンプルとの主な差分
ただし、上記のサンプルとは以下の部分が異なります。

- 環境が p5.js Web　Editor上（メインの JavaScript は、p5.js をベースにしたものが混じる）
- canvas要素は、自前であらかじめ用意
- three.js の描画の更新は、p5.js内の draw() の中で実行

### 実行結果
今回の内容を実行した最終結果は、以下のとおりです。

https://twitter.com/youtoy/status/1614112776796139520

それでは、上記で実行している内容の話に入っていきます。

## 今回行ったこと
それでは、p5.js Web Editor上で実装した内容について書いていきます。

### HTML の内容
p5.js Web Editor上でデフォルトで提供される HTML に対し、three.js を読み込む部分を追加します。

具体的には `<script src="https://threejs.org/build/three.js"></script>` という部分を加えています。

```html
<!DOCTYPE html>
<html lang="en">
  <head>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.5.0/p5.js"></script>
    <script src="https://threejs.org/build/three.js"></script>
    <link rel="stylesheet" type="text/css" href="style.css" />
    <meta charset="utf-8" />
  </head>
  <body>
    <main>
      <canvas id="myCanvas"></canvas>
    </main>
    <script src="sketch.js"></script>
  </body>
</html>
```

ここで追加した行に含まれる URL は、上で掲載していた「 three.js の公式サンプル内の "The result"」の中で、「[live example と書かれた先のページ](https://jsfiddle.net/fxurzeb4/)」で用いられていたものです。
![live example](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/ed9f7bdf-0355-e9b3-b23b-653bba410ae7.png)

### JavaScript の内容
次に JavaScript での実装です。補足は、後のほうに書いていきます。

```javascript

let scene, camera, renderer;
let cube;

function preload() {
  scene = new THREE.Scene();
  camera = new THREE.PerspectiveCamera(
    75,
    window.innerWidth / window.innerHeight,
    0.1,
    1000
  );

  const canvas = document.getElementById("myCanvas");
  renderer = new THREE.WebGLRenderer({ canvas });
  renderer.setSize(window.innerWidth, window.innerHeight);

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

  camera.position.z = 5;
}

function setup() {
  createCanvas(30, 30);
}

function draw() {
  background(220);

  cube.rotation.x += 0.01;
  cube.rotation.y += 0.01;

  renderer.render(scene, camera);
}
```

 three.js の処理のほとんどは `preload()` の中で実装しました（ 今回の内容なら `setup()` の中でも良さそうかもですが）。

また、preload() の外でも使う scene や camera などは、冒頭で宣言しています。

それと、公式のサンプルでは以下のように、`Window.requestAnimationFrame()` で描画の更新が行われていました。 
![Window.requestAnimationFrame()を用いた更新](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/5a1ce8d2-cc19-7430-2133-8c3886fa26c8.png)
今回は、p5.js の描画ループの `draw()` があるため、そちらでこの中の処理を受けもっています。

それと、canvas要素を用いた描画部分の指定は、以下のようにしています。

```javascript
  const canvas = document.getElementById("myCanvas");
  renderer = new THREE.WebGLRenderer({ canvas });
```

これは、[公式ドキュメントの「WebGLRenderer」の部分](https://threejs.org/docs/#api/en/renderers/WebGLRenderer)で、以下で書かれた仕様に準ずるものです。
![WebGLRendererのページ](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/25ddff34-a413-e40e-5c64-34c9b5cc2485.png)

## 描画を p5.js側に取り込む
とりあえず上記の内容で、p5.js Web Editor上で three.js の描画を行うということはできました。

最後に、[冒頭で掲載した PixiJS に関する記事](https://qiita.com/youtoy/items/238a3a083eaf8cd4abf7)の中でもやっていた、three.js のキャンバスで描画した内容を、p5.js のキャンバスで取り込んで描画するという内容も、試しておこうと思います。

対応する内容は、[冒頭で掲載した PixiJS に関する記事](https://qiita.com/youtoy/items/238a3a083eaf8cd4abf7)の中の、[「PixiJS の描画を p5.js側に取り込む」の部分](https://qiita.com/youtoy/items/238a3a083eaf8cd4abf7#pixijs-%E3%81%AE%E6%8F%8F%E7%94%BB%E3%82%92-p5js%E5%81%B4%E3%81%AB%E5%8F%96%E3%82%8A%E8%BE%BC%E3%82%80)と同様ですので、そちらをご参照ください。

その対応を行った後の JavaScript の処理内容は、以下のとおりです。

```javascript
let scene, camera, renderer;
let cube;
let canvas;

function preload() {
  scene = new THREE.Scene();
  camera = new THREE.PerspectiveCamera(
    75,
    window.innerWidth / window.innerHeight,
    0.1,
    1000
  );

  canvas = document.getElementById("myCanvas");
  renderer = new THREE.WebGLRenderer({ canvas });
  renderer.setSize(window.innerWidth, window.innerHeight);

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

  camera.position.z = 5;
}

function setup() {
  canvas.style.display = "none";
  createCanvas(canvas.width, canvas.height);
}

function draw() {
  background(220);
  drawingContext.drawImage(canvas, 0, 0);

  cube.rotation.x += 0.01;
  cube.rotation.y += 0.01;

  renderer.render(scene, camera);
}
```