我试图生成一个带有随机噪声的画布,但是我无法以60fps的速度生成整个画布的随机像素,所以我最终在内存中使用临时画布来生成一个小的64x64磁贴,然后使用上下文填充重复模式,让浏览器将这些字节推送到屏幕,而不是使用javascript引擎。
速度要快得多,即使在全屏设备上,我也可以在iOS设备上获得稳定的60fps,但是我注意到在几分钟之后fps表示会下降直到它变得很慢。
在这个小提琴上,我没有使用应该限制为60Hz的requestAnimationFrame,而是我使用自定义循环,在我的macbook上它以500Hz左右开始并迅速减速以强调问题。
http://jsfiddle.net/Victornpb/m42NT/2/
function loop(){
drawNoise();
}
function drawNoise(){
var context = canvas.getContext("2d");
var pattern = context.createPattern(generatePattern(), "repeat");
context.rect(0,0, canvas.width, canvas.height);
context.fillStyle = pattern;
context.fill()
}
//create a on memory canvas to generate a tile with 64x64 pixels of noise and return it
function generatePattern(){
var canvas = document.createElement("canvas");
canvas.width = 64;
canvas.height = 64;
var context = canvas.getContext("2d");
var image = context.getImageData(0, 0, canvas.width, canvas.height);
var imageData = image.data; // here we detach the pixels array from DOM
var p;
var pixels = canvas.width*canvas.height;
while(pixels--){
p = pixels*4;
imageData[p+0] = Math.random() >= 0.5 ? 255 : 0; // Red
imageData[p+1] = Math.random() >= 0.5 ? 255 : 0; // Green
imageData[p+2] = Math.random() >= 0.5 ? 255 : 0; // Blue
imageData[p+3] = 255; // Alpha
}
image.data = imageData;
context.putImageData(image, 0, 0);
return canvas;
}
答案 0 :(得分:5)
您正在主绘制函数中使用context.rect,而不创建新路径(beginPath)。因此,所有的rect子路径都会添加,并需要在每个帧上重新绘制==>>很快就太慢了。
==>>在使用rect之前使用beginPath()或使用fillRect。
function drawNoise() {
var context = canvas.getContext("2d");
var pattern = context.createPattern(generatePattern(), "repeat");
context.fillStyle = pattern;
context.fillRect(0, 0, canvas.width, canvas.height);
}
请注意,您可以通过不创建画布,并在每次调用generatePattern时创建图像数据,而不是一次又一次地重复使用相同的imageData,从而赢得大量时间。 更重要的是,你只能设置一次alpha:
//create a on memory canvas to generate a tile with 64x64 pixels of noise and return it
var generatePattern = (function () {
var canvas = document.createElement("canvas");
canvas.width = 64;
canvas.height = 64;
var context = canvas.getContext("2d");
var image = context.getImageData(0, 0, canvas.width, canvas.height);
var imageData = image.data; // here we detach the pixels array from DOM
// set the alpha only once.
var p = 0,
pixels = canvas.width * canvas.height;
while (pixels--) {
imageData[p + 3] = 255; // Alpha
p += 4;
}
var _generatePattern = function () {
var p = 0;
var pixels = canvas.width * canvas.height;
var data = imageData;
var rnd = Math.random;
while (pixels--) {
data[p++ ] = rnd() >= 0.5 ? 255 : 0; // Red
data[p++ ] = rnd() >= 0.5 ? 255 : 0; // Green
data[p++ ] = rnd() >= 0.5 ? 255 : 0; // Blue
p++;
}
context.putImageData(image, 0, 0);
return canvas;
}
return _generatePattern;
})();
更新的小提琴在这里:
http://jsfiddle.net/gamealchemist/m42NT/15/
编辑:使用一次调用random()只是为了获得一个随机位是一种过度杀伤:使用math.random()获取一个位域,然后在它为空时重新填充该位域。这里我从Math.random()中获取了21位,因为它没有更多有效位。这样,对于相同的结果,您对此函数(!!)的调用次数减少了21倍。
http://jsfiddle.net/gamealchemist/m42NT/18/
//create a on memory canvas to generate a tile with 64x64 pixels of noise and return it
var generatePattern = (function () {
var canvas = document.createElement("canvas");
canvas.width = 64;
canvas.height = 64;
var context = canvas.getContext("2d");
var image = context.getImageData(0, 0, canvas.width, canvas.height);
var imageData = image.data; // here we detach the pixels array from DOM
// set the alpha only once.
var p = 0,
pixels = canvas.width * canvas.height;
while (pixels--) {
imageData[p + 3] = 255; // Alpha
p += 4;
}
var _generatePattern = function () {
var p = 0;
var pixels = canvas.width * canvas.height;
var data = imageData;
var rnd = Math.random;
var bitsLeft = 0;
var multiplier = (1<<22)-1;
var mask = 0;
while (pixels--) {
if (!bitsLeft) {
bitsLeft=21;
mask= 0 | (Math.random()*multiplier);
}
data[p++ ] = (mask & 1) && 255 ; // Red
data[p++ ] = (mask & 2 ) && 255 ; // Green
data[p++ ] = (mask & 4) && 255; // Blue
p++;
mask>>=3;
bitsLeft-=3;
}
context.putImageData(image, 0, 0);
return canvas;
}
return _generatePattern;
})();
答案 1 :(得分:0)
尝试window.requestAnimationFrame(yourLoopFunction);当你调用循环函数时。
function loop(){
drawNoise();
window.requestAnimationFrame(loop);
}
loop();