gpt4 book ai didi

javascript - 在 html5 Canvas 中渲染大量元素

转载 作者:行者123 更新时间:2023-12-04 10:04:46 25 4
gpt4 key购买 nike

假设您有一个 500x500 的 2D Canvas ,并且您想要为其中的 100000 个元素设置动画,例如您想要创建噪声效果。
考虑下面的代码:

    const canvas = document.getElementById("plane");
let animatelist = [];
animate = function() {
animatelist.forEach((e) => {
e.render();
});
setTimeout(animate, 1000 / 30);
}
animate();
let point = function(plane, x, y, size) {
animatelist.push(this);
this.plane = plane;
this.x = x;
this.y = y;
this.size = size;
this.render = () => {
const context = this.plane.getContext("2d");
this.x = Math.random() * 500;
this.y = Math.random() * 500;
context.fillStyle = "#000";
context.fillRect(this.x, this.y, this.size, this.size);
}
}
for (let i = 0;i < 100000;i++) {
new point(canvas, Math.random() * 500, Math.random() * 500, 0.3);
}

它几乎不能给你 2 或 3 fps,这是 Not Acceptable ,我想知道是否有关于这些动画或平滑渲染大量元素的技巧!

最佳答案

您可以在内存中玩耍,然后在看不见的 Canvas 上绘画。准备好后,将所有字节复制到可见 Canvas 中。
我明白了,你使用了很多随机。这是缓慢的指令。尝试制作一个随机表并实现自己的随机函数

这是一个 12-15 fps 的版本,但我认为您可以通过像素操作来获得更好的性能。所以这段代码基于您的解决方案,但我无法提高 fps,因为函数调用、对象操作和类似的果仁蜜饼太多。 (下面的代码达到 100 fps 以上)

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>sarkiroka</title>
</head>
<body>
<canvas id="plane" width="500" height="500"></canvas>
<script>
// variable and function for speedup
const randomTable = [];
const randomTableLength = 1000007;
const fpsMinimum = 1000 / 30;
for (let i = 0; i < randomTableLength; i++) {
randomTable.push(Math.random() * 500);
}
let randomSeed = 0;

function getNextRandom() {
if (++randomSeed >= randomTableLength) {
randomSeed = 0;
}
return randomTable[randomSeed];
}

// html, dom speedup
const canvas = document.getElementById("plane");
const context = canvas.getContext("2d");
const drawCanvas = document.createElement('canvas');
drawCanvas.setAttribute('width', canvas.getAttribute('width'));
drawCanvas.setAttribute('height', canvas.getAttribute('height'));
const drawContext = drawCanvas.getContext('2d');
drawContext.fillStyle = "#000";

let animatelist = [];
let point = function (x, y, size) {
animatelist.push(this);
this.x = x;
this.y = y;
this.size = size;
this.render = () => {
this.x = getNextRandom();
this.y = getNextRandom();
drawContext.fillRect(this.x, this.y, this.size, this.size);
}
}
for (let i = 0; i < 100000; i++) {
new point(getNextRandom(), getNextRandom(), 0.3);
}

//the animation
let lastBreath = Date.now();
const animateListLength = animatelist.length;
let framesDrawed = 0;
let copied = false;

const maximumCallstackSize = 100;

function continouslyAnimation(deep) {
if (copied) {
drawContext.clearRect(0, 0, 500, 500);
for (let i = 0; i < animateListLength; i++) {
animatelist[i].render();
}
copied = false;
}
framesDrawed++;
let now = Date.now();
if (lastBreath + 15 > now && deep < maximumCallstackSize) {
continouslyAnimation(deep + 1);
} else { // to no hangs browser
lastBreath = now;
setTimeout(continouslyAnimation, 1, 1);
}
}

setInterval(() => {
console.log(framesDrawed);
framesDrawed = 0;
}, 1000);

continouslyAnimation(0);

function copyDrawToVisible() {
context.putImageData(drawContext.getImageData(0, 0, 499, 499), 0, 0);
copied = true;
}

setInterval(copyDrawToVisible, fpsMinimum);
</script>
</body>
</html>

这是一个像素处理解决方案,具有更好的性能(在我的计算机中超过 100 fps,220-245 fps):

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>sarkiroka</title>
</head>
<body>
<canvas id="plane" width="500" height="500"></canvas>
<script>
// variable and function for speedup
const randomTable = [];
const randomTableLength = 1000007;
for (let i = 0; i < randomTableLength; i++) {
randomTable.push(Math.random());
}
let randomSeed = 0;

function getNextRandom() {
if (++randomSeed >= randomTableLength) {
randomSeed = Math.round(Math.random() * 1000);
}
return randomTable[randomSeed];
}

// html, dom speedup
const canvas = document.getElementById("plane");
const context = canvas.getContext("2d");

let framesDrawed = 0;

function drawNoise() {
context.clearRect(0, 0, 500, 500);
let imageData = context.createImageData(499, 499);
let data = imageData.data;
for (let i = 0, length = data.length; i < length; i += 4) {
if (0.1 > getNextRandom()) {
data[i] = 0;
data[i + 1] = 0;
data[i + 2] = 0;
data[i + 3] = 255;
}
}
context.putImageData(imageData, 0, 0);
framesDrawed++;
}

setInterval(drawNoise, 0);
setInterval(() => {
console.log('fps', framesDrawed);
framesDrawed = 0;
}, 1000)
</script>
</body>
</html>


说明:对于噪声,您不需要每个彩色像素的函数/对象。相信统计和随机。在我的示例中,10% 的像素是彩色的,但我们不知道渲染前有多少像素。但这并不重要。远远望去,简直就是完美。最重要的是:它可以达到更高的 fps。

一般建议:
  • 哪些代码重复多次,尽你所能组织起来
  • 在内存中完成绘图后仅在 Canvas 上绘图
  • 测量慢的并优化它,只有它
  • 关于javascript - 在 html5 Canvas 中渲染大量元素,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61642773/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com