みかづきブログ・カスタム

基本的にはちょちょいのほいです。

A-FrameでCanvasをテクスチャーに設定して動的に更新する 🎥

f:id:kimizuka:20201130222254j:plain

以前、Three.jsでCanvasをテクスチャーに設定した場合、material.map.needsUpdateをtrueに設定すれば動的に更新できることを調べました。

blog.kimizuka.org

今回は、それのA-Frame版です。
A-Frameも内部はThree.jsを使っているので、material.map.needsUpdateをtrueにしなければならないことは火を見るよりも明らかなのですが、どうやって渡すか試行錯誤しました。

結果、A-Frameのオブジェクトには、getObject3Dたるメソッドがあり、getObject3D('mesh')でメッシュを取得できるようです。

メッシュさえ取得してしまえば、

object.getObject3D('mesh').material.map.needsUpdate = true;

という感じで、material.map.needsUpdateにtrueを入れることは楽々です。
ただ、毎フレーム設定する必要があるので、

<a-scene>
  <a-assets>
    <canvas id="canvas"></canvas>
  </a-assets>
</a-scene>
<script>
  AFRAME.registerComponent('plane', {
    init: function () {
      this.canvas = document.getElementById('canvas');
      this.ctx = canvas.getContext('2d');
    },
    tick: function () {
      const material = this.el.getObject3D('mesh').material;
      const fontSize = 24;

      this.canvas.width = this.canvas.width;
      this.canvas.height = this.canvas.height;

      this.ctx.save();
        this.ctx.font = `${fontSize}px sans-serif`;
        this.ctx.fillText(Date.now(), 0, fontSize);
      this.ctx.restore();

      if (!material.map) {
        return;
      }

      material.map.needsUpdate = true;
    }
  });

  const plane = document.createElement('a-plane');

  plane.setAttribute('plane', 'plane');
  plane.setAttribute('material', 'shader: flat; src: #canvas;');

  document.getElementsByTagName('a-scene')[0].appendChild(plane);
</script>

という感じで、tickをうまく使うと良いと思われます。