MindARでThreeJS FaceMeshにcanvasの画像を表示させる

# FaceMeshでフェイスペイントをしたい
canvasに描いた画像をFaceMeshに表示する「ARフェイスペイント」です。
https://kaihatuiinkai.jp/ardeasobou/facepaint.html
![AR_facepaint.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/509199/ff7cd70b-d299-a492-92dc-4e175093f5fd.png)

この基本を解説します。
# MindARの「ThreeJS FaceMesh」が基本です
MindAR「Documentation」の「ThreeJS FaceMesh」のページが基本になります。
https://hiukim.github.io/mind-ar-js-doc/more-examples/threejs-face-facemesh
```html:face_mesh.html

<html>
  <head>
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <script type="importmap">
    {
      "imports": {
        "three": "https://unpkg.com/three@0.160.0/build/three.module.js",
        "three/addons/": "https://unpkg.com/three@0.160.0/examples/jsm/",
        "mindar-face-three":"https://cdn.jsdelivr.net/npm/mind-ar@1.2.5/dist/mindar-face-three.prod.js"
      }
    }
    </script>
    <script type="module">
      import * as THREE from "three";
      import { MindARThree } from "mindar-face-three";
      const mindarThree = new MindARThree({
      	container: document.querySelector("#container"),
      });
      const {renderer, scene, camera} = mindarThree;
      const light = new THREE.HemisphereLight( 0xffffff, 0xbbbbff, 1 );
      scene.add(light);
      const faceMesh = mindarThree.addFaceMesh();
      const texture = new THREE.TextureLoader().load("https://cdn.jsdelivr.net/gh/hiukim/mind-ar-js@1.2.5/examples/face-tracking/assets/canonical_face_model_uv_visualization.png");
      faceMesh.material.map = texture;
      faceMesh.material.transparent = true;
      faceMesh.material.needsUpdate = true;
      scene.add(faceMesh);
      const start = async() => {
        await mindarThree.start();
        renderer.setAnimationLoop(() => {
          renderer.render(scene, camera);
        });
      }
      start();
    </script>
    <style>
      body {
      	margin: 0;
      }
      #container {
        width: 100vw;
        height: 100vh;
        position: relative;
        overflow: hidden;
      }
    </style>
  </head>
  <body>
    <div id="container">
    </div>
  </body>
</html>
```
作動確認用のサンプルはこちらです。
https://kaihatuiinkai.jp/ardeasobou/face_mesh.html
顔を動かすとメッシュが追随します。目を見開いたり、口を開けたりするとメッシュが変形します。

# canvasに描いた画像を表示する
次に、canvasに描いた文字をメッシュの上に表示させてみます。
参考サイト「Three.jsで常に正面を向く長方形の文字ラベルを描画する」
https://astatsuya.medium.com/three-js%E3%81%A7%E5%B8%B8%E3%81%AB%E6%AD%A3%E9%9D%A2%E3%82%92%E5%90%91%E3%81%8F%E9%95%B7%E6%96%B9%E5%BD%A2%E3%81%AE%E6%96%87%E5%AD%97%E3%83%A9%E3%83%99%E3%83%AB%E3%82%92%E6%8F%8F%E7%94%BB%E3%81%99%E3%82%8B-fa606ed6752

scriptの一部を変えるだけです。
```html:face_mesh2.html
    <script type="module">
      import * as THREE from "three";
      import { MindARThree } from "mindar-face-three";
      const mindarThree = new MindARThree({
        container: document.querySelector("#container"),
      });
      const {renderer, scene, camera} = mindarThree;
      const light = new THREE.HemisphereLight( 0xffffff, 0xbbbbff, 1 );
      scene.add(light);
      const faceMesh = mindarThree.addFaceMesh();
      // 貼り付けるcanvasを作成
      const createCanvasForTexture = (canvasWidth, canvasHeight, text, fontSize) => {
        const canvasForText = document.createElement("canvas");
        const ctx = canvasForText.getContext("2d");
        ctx.canvas.width = canvasWidth;
        ctx.canvas.height = canvasHeight; 
        ctx.fillStyle = "rgba(0, 0, 0, 0)";
        ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height);
        ctx.fillStyle = "black";
        ctx.font = `${fontSize}px serif`;
        ctx.fillText(
          text,
          (canvasWidth - ctx.measureText(text).width) / 2,
          canvasHeight / 2 + ctx.measureText(text).actualBoundingBoxAscent / 2
        );
        return canvasForText;
      };
      // 表示する文字
      var texture = new THREE.CanvasTexture(createCanvasForTexture(512, 512, "Hello World!", 40));
      faceMesh.material.map = texture;
      faceMesh.material.transparent = true;
      faceMesh.material.needsUpdate = true;
      scene.add(faceMesh);
      const start = async() => {
        await mindarThree.start();
        renderer.setAnimationLoop(() => {
          renderer.render(scene, camera);
        });
      }
      start();
    </script>
```
作動確認用のサンプルはこちらです。
https://kaihatuiinkai.jp/ardeasobou/face_mesh2.html
「Hello World!」文字が顔表面に沿って表示されます。

# 別canvasに描いた画像を表示する
別canvasが書き換わったとき、FaceMeshに画像を変えるために、renderer.setAnimationLoop内に記載します。
```html:face_mesh3.html
<html>
  <head>
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <script type="importmap">
    {
      "imports": {
        "three": "https://unpkg.com/three@0.160.0/build/three.module.js",
        "three/addons/": "https://unpkg.com/three@0.160.0/examples/jsm/",
        "mindar-face-three":"https://cdn.jsdelivr.net/npm/mind-ar@1.2.5/dist/mindar-face-three.prod.js"
      }
    }
    </script>
    <script type="module">
      import * as THREE from "three";
      import { MindARThree } from "mindar-face-three";
      const mindarThree = new MindARThree({
        container: document.querySelector("#container"),
      });
      const {renderer, scene, camera} = mindarThree;
      const light = new THREE.HemisphereLight( 0xffffff, 0xbbbbff, 1 );
      scene.add(light);
      const faceMesh = mindarThree.addFaceMesh();
      // 貼り付けるcanvasを作成。
      const canvasForText = document.createElement("canvas");
      const ctx = canvasForText.getContext("2d");
      ctx.canvas.width  = 512;
      ctx.canvas.height = 512;
      var image = document.querySelector("#drawArea").getContext("2d").getImageData(0, 0, 512, 512);
      //  canvasにデータをコピー
      const createCanvasForTexture = () => {
        image = document.querySelector("#drawArea").getContext("2d").getImageData(0, 0, 512, 512);
        ctx.putImageData(image, 0, 0);
        return canvasForText;
      };

      var texture = new THREE.CanvasTexture(createCanvasForTexture());
      texture.colorSpace = THREE.SRGBColorSpace;  // 色の感じを変える
      faceMesh.material.map = texture;
      faceMesh.material.transparent = true;
      faceMesh.material.needsUpdate = true;
      scene.add(faceMesh);
      const start = async() => {
        await mindarThree.start();
        renderer.setAnimationLoop(() => {
          var texture = new THREE.CanvasTexture(createCanvasForTexture());
          faceMesh.material.map = texture;
          renderer.render(scene, camera);
        });
      }
      start();
    </script>
    <style>
      body {
      	margin: 0;
      }
      #container {
        width: 100vw;
        height: 100vh;
        position: relative;
        overflow: hidden;
      }
    </style>
  </head>
  <body>
    <div id="container" style="width: 600px;height: 400px;">
    </div>
    <div style="position:absolute; top: 0px; left:0px">
      <canvas id="drawArea" width= "512px" height= "512px"
           style="z-index: 2;position:absolute; top:0px; left:600px;
          border: 1px solid rgba(0,0,0,1);
          background-color: rgba(255,255,255,0);">
      </canvas>
    </div>
    <script>
      // 別canvasに文字を表示
      const drawArea = document.querySelector("#drawArea");
      const ctxDrawArea = drawArea.getContext("2d");
      ctxDrawArea.fillStyle = "black";
      ctxDrawArea.font = "50px serif";
      ctxDrawArea.fillText("Hello World!", 100, 250);
    </script>
  </body>
</html>
```
作動確認用のサンプルはこちらです。
https://kaihatuiinkai.jp/ardeasobou/face_mesh3.html
別canvasに描いた「Hello World!」の文字が顔表面に沿って表示されます。
あとは、この「別canvas」に図を描く機能を追加していきます。