首页 > 解决方案 > AFrame:如何以编程方式创建画布纹理平面网格

问题描述

我不太了解 aframe 如何在初始化时从 JavaScript 完成事情。我创建了一个网格组件来创建 NxM 平面,每个平面都有自己的纹理画布。但由于某种原因,即使画布是独一无二的,每架飞机 1 个,它们在每架飞机上被随机重复使用

我应该看到的是一个像这样的网格

+---+ +---+ +---+
| 6 | | 7 | | 8 |
+---+ +---+ +---+
+---+ +---+ +---+
| 3 | | 4 | | 5 |
+---+ +---+ +---+
+---+ +---+ +---+
| 0 | | 1 | | 2 |
+---+ +---+ +---+

我看到的是类似

在此处输入图像描述

我可能正在做一些愚蠢的事情。这是代码。注意:由于 aframe 的工作方式,它都停留在 HTML 部分。

<script src="https://aframe.io/releases/0.8.0/aframe.min.js"></script>
<script>
AFRAME.registerComponent('grid', {
  schema: {
    across: {type: 'int', default: 3},
    down: {type: 'int', default: 3},
  },
  init() {
    const data = this.data;
    const across = data.across;
    const down = data.down;
    const needed = across * down;
    for (let i = 0; i < needed; ++i) {
      const canvas = document.createElement('canvas');
      canvas.width = 256;
      canvas.height = 256;
      canvas.id = `c${Date.now()}`;
      const ctx = canvas.getContext('2d');
      ctx.fillStyle = `hsl(${i / needed * 360 | 0}deg,100%,50%)`;
      ctx.fillRect(0, 0, 256, 256);
      ctx.fillStyle = `hsl(${Math.random() * 360 | 0}deg,100%,80%)`;
      ctx.fillStyle = 'black';
      ctx.font = '200px sans-serif';
      ctx.textAlign = 'center';
      ctx.textBaseline = 'middle';
      ctx.fillText(i, 128, 128);
      const elem = document.createElement('a-entity');
      elem.setAttribute('geometry', {
        primitive: 'plane',
        height: 1,
        width: 1,
      });
      elem.setAttribute('material', {
        shader: 'flat',
        src: canvas,
      });
      this.el.appendChild(elem);
      const x = i % across;
      const y = i / across | 0;
      const u = x / (across - 1);
      const v = y / (down - 1);
      const px = across * (u - .5);
      const py = down * (v - .5);
      const pz = 0;
      elem.setAttribute('position', {x: px, y: py, z: pz});
    }
  },
});
</script>
<a-scene>
  <a-entity grid position="0 1.5 -4"></a-entity>
</a-scene>

我还尝试将画布添加到 DOM 并通过分配 id 进行引用。相关线路是

  // make up an ID
  canvas.id = `c${Date.now()}`;

  // add to document
  document.body.appendChild(canvas);

  // make the src the id of the canvas
  elem.setAttribute('material', {
    shader: 'flat',
    src: `#${canvas.id}`,
  });

但它有同样的问题

在此处输入图像描述

<script src="https://aframe.io/releases/0.8.0/aframe.min.js"></script>
<script>
AFRAME.registerComponent('grid', {
  schema: {
    across: {type: 'int', default: 3},
    down: {type: 'int', default: 3},
  },
  init() {
    const data = this.data;
    const across = data.across;
    const down = data.down;
    const needed = across * down;
    for (let i = 0; i < needed; ++i) {
      const canvas = document.createElement('canvas');
      canvas.width = 256;
      canvas.height = 256;
      canvas.id = `c${Date.now()}`;
      document.body.appendChild(canvas);
      const ctx = canvas.getContext('2d');
      ctx.fillStyle = `hsl(${i / needed * 360 | 0}deg,100%,50%)`;
      ctx.fillRect(0, 0, 256, 256);
      ctx.fillStyle = `hsl(${Math.random() * 360 | 0}deg,100%,80%)`;
      ctx.fillStyle = 'black';
      ctx.font = '200px sans-serif';
      ctx.textAlign = 'center';
      ctx.textBaseline = 'middle';
      ctx.fillText(i, 128, 128);
      const elem = document.createElement('a-entity');
      elem.setAttribute('geometry', {
        primitive: 'plane',
        height: 1,
        width: 1,
      });
      elem.setAttribute('material', {
        shader: 'flat',
        src: `#${canvas.id}`,
      });
      this.el.appendChild(elem);
      const x = i % across;
      const y = i / across | 0;
      const u = x / (across - 1);
      const v = y / (down - 1);
      const px = across * (u - .5);
      const py = down * (v - .5);
      const pz = 0;
      elem.setAttribute('position', {x: px, y: py, z: pz});
    }
  },
});
</script>
<a-scene>
  <a-entity grid position="0 1.5 -4"></a-entity>
</a-scene>

标签: aframe

解决方案


我认为这是因为 a-frame 创建实体的速度如此之快,以至于 Date.now 不是唯一的。

在循环之外,尝试:

let id = 0;

然后对于 id:

canvas.id = `c${id++}`;

它似乎按预期工作。

<script src="https://aframe.io/releases/0.8.0/aframe.min.js"></script>
<script>
AFRAME.registerComponent('grid', {
  schema: {
    across: {type: 'int', default: 3},
    down: {type: 'int', default: 3},
  },
  init() {
    const data = this.data;
    const across = data.across;
    const down = data.down;
    const needed = across * down;
    let id = 0;
    for (let i = 0; i < needed; ++i) {
      const canvas = document.createElement('canvas');
      canvas.width = 256;
      canvas.height = 256;
      canvas.id = `c${id++}`;
      document.body.appendChild(canvas);
      const ctx = canvas.getContext('2d');
      ctx.fillStyle = `hsl(${i / needed * 360 | 0}deg,100%,50%)`;
      ctx.fillRect(0, 0, 256, 256);
      ctx.fillStyle = `hsl(${Math.random() * 360 | 0}deg,100%,80%)`;
      ctx.fillStyle = 'black';
      ctx.font = '200px sans-serif';
      ctx.textAlign = 'center';
      ctx.textBaseline = 'middle';
      ctx.fillText(i, 128, 128);
      const elem = document.createElement('a-entity');
      elem.setAttribute('geometry', {
        primitive: 'plane',
        height: 1,
        width: 1,
      });
      elem.setAttribute('material', {
        shader: 'flat',
        src: `#${canvas.id}`,
      });
      this.el.appendChild(elem);
      const x = i % across;
      const y = i / across | 0;
      const u = x / (across - 1);
      const v = y / (down - 1);
      const px = across * (u - .5);
      const py = down * (v - .5);
      const pz = 0;
      elem.setAttribute('position', {x: px, y: py, z: pz});
    }
  },
});
</script>
<a-scene>
  <a-entity grid position="0 1.5 -4"></a-entity>
</a-scene>


推荐阅读