如何在 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>
我需要一次显示 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>