PlayCanvas のシンプルな Hello World のサンプルを p5.js Web Editor上で動かしてみる

この記事の内容は、タイトルのとおり、p5.js Web Editor上で PlayCanvas のシンプルな Hello World のサンプルを動かしてみた話です。

## 余談
余談ですが、他に PixiJS・three.js と、p5.js とを組み合わせるというのを試してみたことがあります。

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

## PlayCanvas のシンプルな Hello World のサンプル
今回のメインとなる、PlayCanvas のシンプルな Hello World のサンプルについて、まずは記載します。具体的には、以下に掲載されたサンプルです。

●engine/README-ja.md at main · playcanvas/engine · GitHub
　https://github.com/playcanvas/engine/blob/main/README-ja.md

具体的には、以下の内容です。また、この内容は[「The Hello World of 3D」というタイトルの CodePen のページ](https://codepen.io/playcanvas/pen/NPbxMj)にアクセスすれば、簡単に動作を確認することもできます。

```html
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>PlayCanvas Hello Cube</title>
    <meta name='viewport' content='width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no' />
    <style>
        body {
            margin: 0;
            overflow: hidden;
        }
    </style>
    <script src='https://code.playcanvas.com/playcanvas-stable.min.js'></script>
</head>
<body>
    <canvas id='application'></canvas>
    <script>
        // create a PlayCanvas application
        const canvas = document.getElementById('application');
        const app = new pc.Application(canvas);
        // fill the available space at full resolution
        app.setCanvasFillMode(pc.FILLMODE_FILL_WINDOW);
        app.setCanvasResolution(pc.RESOLUTION_AUTO);
        // ensure canvas is resized when window changes size
        window.addEventListener('resize', () => app.resizeCanvas());
        // create box entity
        const box = new pc.Entity('cube');
        box.addComponent('model', {
            type: 'box'
        });
        app.root.addChild(box);
        // create camera entity
        const camera = new pc.Entity('camera');
        camera.addComponent('camera', {
            clearColor: new pc.Color(0.1, 0.1, 0.1)
        });
        app.root.addChild(camera);
        camera.setPosition(0, 0, 3);
        // create directional light entity
        const light = new pc.Entity('light');
        light.addComponent('light');
        app.root.addChild(light);
        light.setEulerAngles(45, 0, 0);
        // rotate the box according to the delta time since the last frame
        app.on('update', dt => box.rotate(10 * dt, 20 * dt, 30 * dt));
        app.start();
    </script>
</body>
</html>
```

これを p5.js Web Editor で動かしていきます。

### p5.js Web Editor でとりあえず動作させる
上記のサンプルを p5.js Web　Editor で動かす際に、HTML・JavaScript（index.html と sketch.js）を書きかえます。

#### HTML
p5.js Web Editor のデフォルトの HTML に関して、変更した部分は以下の 2つです。

1. CDN からのライブラリの読み込みの実行
1. PlayCanvas用のキャンバス要素の追加

具体的には、以下のとおりです。

```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://code.playcanvas.com/playcanvas-stable.min.js"></script>
    <link rel="stylesheet" type="text/css" href="style.css" />
    <meta charset="utf-8" />
  </head>
  <body>
    <main><canvas id="application"></canvas></main>
    <script src="sketch.js"></script>
  </body>
</html>
```

#### JavaScript
p5.js Web Editor でデフォルトで用意される JavaScript に関して、変更した主な内容は以下のとおりです。

1. 上記の PlayCanvas のサンプルのほとんどを、setup() の中に記載
1. オブジェクトを回転させる処理を draw() の中に記載

```javascript
let box;

function setup() {
  createCanvas(20, 20);

  const canvas = document.getElementById("application");
  const app = new pc.Application(canvas);

  app.setCanvasFillMode(pc.FILLMODE_FILL_WINDOW);
  app.setCanvasResolution(pc.RESOLUTION_AUTO);

  window.addEventListener("resize", () => app.resizeCanvas());

  box = new pc.Entity("cube");
  box.addComponent("model", {
    type: "box",
  });
  app.root.addChild(box);

  const camera = new pc.Entity("camera");
  camera.addComponent("camera", {
    clearColor: new pc.Color(0.1, 0.1, 0.1),
  });
  app.root.addChild(camera);
  camera.setPosition(0, 0, 3);

  const light = new pc.Entity("light");
  light.addComponent("light");
  app.root.addChild(light);
  light.setEulerAngles(45, 0, 0);

  app.start();
}

function draw() {
  background(220);

  box.rotate(0.5, 1, 1.5);
}
```

ここまでは、p5.js のキャンバスは利用せず、PlayCanvas用に用意したキャンバス上での描画を行っています。これを、p5.js のキャンバスに描画する形に変更していきます。

## p5.js のキャンバス上で描画させる
PlayCanvas の描画結果を、p5.js のキャンバス上で描画させてみます。

HTML はそのままで、JavaScript に少し変更を加えます。

```javascript
let canvasPS;
let box;

function setup() {
  createCanvas(windowWidth, windowHeight);

  canvasPS = document.getElementById("application");
  canvasPS.style.visibility = "hidden";
  canvasPS.style.position = "absolute";

  const app = new pc.Application(canvasPS);

  app.setCanvasFillMode(pc.FILLMODE_FILL_WINDOW);
  app.setCanvasResolution(pc.RESOLUTION_AUTO);

  window.addEventListener("resize", () => app.resizeCanvas());

  box = new pc.Entity("cube");
  box.addComponent("model", {
    type: "box",
  });
  app.root.addChild(box);

  const camera = new pc.Entity("camera");
  camera.addComponent("camera", {
    clearColor: new pc.Color(0.1, 0.1, 0.1),
  });
  app.root.addChild(camera);
  camera.setPosition(0, 0, 3);

  const light = new pc.Entity("light");
  light.addComponent("light");
  app.root.addChild(light);
  light.setEulerAngles(45, 0, 0);

  app.start();
}

function draw() {
  background(220);
  drawingContext.drawImage(canvasPS, 0, 0, width, height);

  box.rotate(0.5, 1, 1.5);
}

function windowResized() {
  resizeCanvas(windowWidth, windowHeight);
}
```

上記で行った主な対応は以下の通りです。

- p5.js のキャンバスのサイズを、PlayCanvas のキャンバスと同様に画面いっぱいになるように変更（リサイズ時のサイズ変更も追加）
- PlayCanvas のキャンバスを不可視に
- PlayCanvas のキャンバスの描画内容を、 `drawingContext.drawImage()` で p5.js のキャンバスに描画

### 実行結果
実行結果は、このようになりました。

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