如何在 phaser3/webgl 的网格中显示 250k 个单元格?

How to display 250k cells in a grid with phaser3/webgl?

我需要一次显示 250k cells/rectangles,当绘制超过 20k 个矩形时,帧率下降到 30fps 以下。

我什么都没有 运行 一旦绘制了网格,但 fps 仍然很低,不知道为什么。我还需要偶尔更新一些单元格颜色。

我试过使用线而不是矩形(垂直和水平线形成网格),但性能似乎差不多。

代码:https://playcode.io/638898/

假设目前无法以 30fps 的速度绘制这么多矩形,还有哪些其他替代方法?

谢谢。

解决方法: 我最终使用线条而不是矩形,就像 Denis answer 建议在显示 250k 个单元格时超过 60fps。

var config = {
  width: 1200,
  height: 1200,
  type: Phaser.AUTO,
  parent: '#canvas',
  scene: {
    create: create,
    update: update,
  },
};

var game = new Phaser.Game(config);
var graphics;

// Change size.
let isize = 600;

let data = [];

data = [...Array(isize)].map(x => Array(isize).fill(0));

let hspace = 5;
let size = {
  x: isize,
  y: isize
}

let fps = 0;
let fpsText;

function create() {

  graphics = this.add.graphics({
    lineStyle: {
      width: 1,
      color: 0xffffff,
      alpha: 1
    }
  });

  // Draw rectangles.
  for (let ix = 0; ix < size.x; ix++) {
    requestAnimationFrame(() => {
      graphics.beginPath();
      graphics.moveTo(ix * hspace, 0);
      graphics.lineTo(ix * hspace, size.y * hspace);
      graphics.stroke()
    });
  }

  for (let iy = 0; iy < size.y; iy++) {
    requestAnimationFrame(() => {
      graphics.beginPath();
      graphics.moveTo(0, iy * hspace);
      graphics.lineTo(size.x * hspace, iy * hspace);
      graphics.stroke()
    });
  }

  fpsText = this.add.text(50, 50, 'Static Text Object', { fontFamily: 'Arial', fontSize: 48, color: '#00ff00' });

  this.cameras.main.setZoom(.3);
  this.cameras.main.setPosition(-400, -400);

  // Move camera with mouse drag.
  this.input.on('pointermove', (pointer) => {
    if (pointer.isDown) {
      this.cameras.main.scrollX -= (pointer.position.x - pointer.prevPosition.x) * 1.5;
      this.cameras.main.scrollY -= (pointer.position.y - pointer.prevPosition.y) * 1.5;
    }
  })
}

function update() {
  fpsText.setText(Math.floor(this.game.loop.actualFps) + "fps");
}
<script src="https://cdn.jsdelivr.net/npm/phaser@3.23.0/dist/phaser.js"></script>

调用 requestAnimationFrame 是完全多余的,因为 create 函数不会向显示器显示任何内容。它只被调用一次。

通过减少渲染调用次数来减少 GPU 状态变化。 graphics.stroke 是一个状态改变函数,因为所有的行都使用相同的样式,你只需要调用一次 stroke 而不是多次调用

注意 我不熟悉 Phaser 的内部结构,它可能会也可能不会强制 stroke 上的状态发生变化,但是其他 API 会挑衅地这样做!有意识,写得有效率就好。

const config = {
  width: 1200,  height: 1200,
  type: Phaser.AUTO,
  parent: '#canvas',
  scene: {create, update},
};
const game = new Phaser.Game(config);
const isize = 600, hspace = 50, size = {x: isize, y: isize};
var graphics, fps = 0, fpsText;

function create() {
  var i = Math.max(size.x, size.y);
  graphics = this.add.graphics({ lineStyle: {width: 1, color: 0xffffff, alpha: 1}});

  graphics.beginPath();
  while (i--) {
      if (i < size.x) {
          graphics.moveTo(i * hspace, 0);
          graphics.lineTo(i * hspace, size.y * hspace);
      }
      if (i < size.y) {
          graphics.moveTo(0, i * hspace);
          graphics.lineTo(size.x * hspace, i * hspace);
      }
  }
  graphics.stroke(); 

  fpsText = this.add.text(50, 50, 'Static Text Object', { fontFamily: 'Arial', fontSize: 48, color: '#00ff00' });

  this.cameras.main.setZoom(.3);
  this.cameras.main.setPosition(-400, -400);
  this.input.on('pointermove', pointer => {
    if (pointer.isDown) {
      this.cameras.main.scrollX -= (pointer.position.x - pointer.prevPosition.x) * 1.5;
      this.cameras.main.scrollY -= (pointer.position.y - pointer.prevPosition.y) * 1.5;
    }
  })
}

function update() {
    fpsText.setText((this.game.loop.actualFps | 0) + "fps");
}
<script src="https://cdn.jsdelivr.net/npm/phaser@3.23.0/dist/phaser.js"></script>