我有一个名为 generateNoise()
的函数,它创建一个 Canvas 元素并为其绘制随机 RGBA 值;其中,给出了噪音的外观。
我的问题
什么是无限地动画噪声以给出运动外观的最佳方法。让它有更多的生命?
function generateNoise(opacity) {
if(!!!document.createElement('canvas').getContext) {
return false;
}
var canvas = document.createElement('canvas'),
ctx = canvas.getContext('2d'),
x,y,
r,g,b,
opacity = opacity || .2;
canvas.width = 55;
canvas.height = 55;
for (x = 0; x < canvas.width; x++){
for (y = 0; y < canvas.height; y++){
r = Math.floor(Math.random() * 255);
g = Math.floor(Math.random() * 255);
b = Math.floor(Math.random() * 255);
ctx.fillStyle = 'rgba(' + r + ',' + b + ',' + g + ',' + opacity + ')';
ctx.fillRect(x,y,1,1);
}
}
document.body.style.backgroundImage = "url(" + canvas.toDataURL("image/png") + ")";
}
generateNoise(.8);
最佳答案
1/2017 更新:我重写了整个答案,因为它开始变得相当困惑,并解决了评论中指出的一些问题。原答案可见here .新答案本质上具有相同的代码,但有所改进,并且通过一些新技术,人们利用了自该答案首次发布以来可用的新功能。
对于“真正的”随机外观,我们需要使用像素级渲染。我们可以使用 32 位无符号缓冲区而不是 8 位来优化这一点,我们还可以在更新的浏览器中关闭 alpha channel ,从而加快整个过程(对于旧浏览器,我们可以简单地为 Canvas 元素)。
我们在主循环外创建了一个可重用的 ImageData
对象,因此主要成本仅为 putImageData()
而不是在循环内。
var ctx = c.getContext("2d", {alpha: false}); // context without alpha channel.
var idata = ctx.createImageData(c.width, c.height); // create image data
var buffer32 = new Uint32Array(idata.data.buffer); // get 32-bit view
(function loop() {
noise(ctx);
requestAnimationFrame(loop)
})()
function noise(ctx) {
var len = buffer32.length - 1;
while(len--) buffer32[len] = Math.random() < 0.5 ? 0 : -1>>0;
ctx.putImageData(idata, 0, 0);
}
/* for browsers wo/2d alpha disable support */
#c {background:#000}
<canvas id=c width=640 height=320></canvas>
一个非常有效的方法,以一些内存为代价,但降低了 CPU 的成本,是用噪声一次预渲染一个更大的屏幕外 Canvas ,然后将那个 使用随机整数偏移将 Canvas 放入主 Canvas 中。
它需要一些额外的准备步骤,但循环可以完全在 GPU 上运行。
var w = c.width;
var h = c.height;
var ocanvas = document.createElement("canvas"); // create off-screen canvas
ocanvas.width = w<<1; // set offscreen canvas x2 size
ocanvas.height = h<<1;
var octx = ocanvas.getContext("2d", {alpha: false});
var idata = octx.createImageData(ocanvas.width, ocanvas.height);
var buffer32 = new Uint32Array(idata.data.buffer); // get 32-bit view
// render noise once, to the offscreen-canvas
noise(octx);
// main loop draw the offscreen canvas to random offsets
var ctx = c.getContext("2d", {alpha: false});
(function loop() {
var x = (w * Math.random())|0; // force integer values for position
var y = (h * Math.random())|0;
ctx.drawImage(ocanvas, -x, -y); // draw static noise (pun intended)
requestAnimationFrame(loop)
})()
function noise(ctx) {
var len = buffer32.length - 1;
while(len--) buffer32[len] = Math.random() < 0.5 ? 0 : -1>>0;
ctx.putImageData(idata, 0, 0);
}
/* for browsers wo/2d alpha disable support */
#c {background:#000}
<canvas id=c width=640 height=320></canvas>
请注意,尽管使用后一种技术,您可能会遇到“卡住”的风险,因为新的随机偏移量与前一种随机偏移量相似。要解决此问题,请为随机位置设置标准以禁止连续放置太近的位置。
关于javascript - 动画 Canvas 看起来像电视噪音,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22003491/