Javascript 如何进行优化的画布像素渲染?

Javascript 如何进行优化的画布像素渲染?,javascript,canvas,Javascript,Canvas,我正在研究一种用优化过的方法画像素的方法, 降低fps下降的概率。我使用2d,因为它比webgl上下文更简单。以下是我尝试过的代码: <script> document.write(".") document.body.innerHTML="" document.body.style.margin="0 0 0 0" c=document.createElement("canvas") document.body.appendChild(c) ctx=c.getContext("2d

我正在研究一种用优化过的方法画像素的方法, 降低fps下降的概率。我使用2d,因为它比webgl上下文更简单。以下是我尝试过的代码:

<script>
document.write(".")
document.body.innerHTML=""
document.body.style.margin="0 0 0 0"
c=document.createElement("canvas")
document.body.appendChild(c)
ctx=c.getContext("2d")
setInterval(function(){
c.width=innerWidth
c.height=innerHeight
for(x=0;x<innerWidth;x++){
for(y=0;y<innerHeight;y++){
ctx.fillStyle="rgba(0,0,0,1)"
ctx.fillRect(x,y,x+1,y+1)
}}},1)
</script>

文件。填写(“.”)
document.body.innerHTML=“”
document.body.style.margin=“0”
c=document.createElement(“画布”)
document.body.appendChild(c)
ctx=c.getContext(“2d”)
setInterval(函数(){
c、 宽度=内部宽度
c、 高度=内部高度
对于(x=0;x
(()=>{
文件。填写(“.”)
document.body.innerHTML=“”
document.body.style.margin=“0”
c=document.createElement(“画布”)
document.body.appendChild(c)
ctx=c.getContext(“2d”)
c、 宽度=内部宽度
c、 高度=内部高度
x=0;
y=0;
函数drawPixel(){
ctx.fillStyle=“rgba(0,0,0,1)”;
ctx.fillRect(x,y,x+1,y+1);
x++;
如果(x>innerWidth){
x=0;
y++;
}
如果(y<内部高度)
请求动画帧(drawPixel);
}
requestAnimationFrame(drawPixel)
})()

试试这个,它几乎和你做的一样。你需要更改一些部分以获得更好的性能,我刚刚调整了你的代码以使用requestAnimationFrame。

一次绘制一个像素的最快方法是创建一个图像数据对象,并添加一个类型化数组,将每个像素作为32位整数保存

// assuming the ctx has been defined
var pixelData = ctx.getImageData(0, 0, ctx.canvas.width, ctx.canvas.height);    
pixelData.data32 = new Uint32Array(pixelData.data.buffer); // create 32bit pixel
填充缓冲像素数据的最快方法是通过
typedArray.fill
函数

 const white = 0xFFFFFFFF;
 pixelData.data32.fill(white);
还是绿色

 const green = 0xFF00FF00;
 pixelData.data32.fill(green);
通过像素的坐标设置像素

  function setPixel(x,y,color){
       pixelData.data32[x + y * ctx.canvas.width] = color; 
  }
  setPixel(10,10,0xFFFFFFFF);
要将像素移动到画布,请使用

 ctx.putImageData(pixelData,0,0);

32位像素的颜色通道顺序为ABGR,因此
0xFF000000
为黑色
0x00000000
为透明,
0xFFFF0000
为蓝色,
0xFF00FF00
为绿色,
0xFF0000FF
为红色。(注意,在一些非常罕见的情况下,颜色可能会根据硬件的端度而变化。)

你的代码就是
ctx.fillStyle='black';ctx.fillRect(0,0,c.width,c.height)
。但是我想你还需要一些东西。例如,如果你需要每个像素有不同的值,那么直接从imageData开始工作,你将
把它放到你的上下文中:
var data=ctx.createImageData(width,height)然后遍历所有像素数据([r,g,b,a,r,g,b,a…]),甚至使用uint32数组,最后
ctx.putImageData(数据,x,y)发生这种情况是因为setInterval阻止浏览器渲染。您必须使用requestAnimationFrame@Kaiido是的,我需要一个像素渲染上下文,它按照我喜欢的方式渲染像素,侦听条件和变量。@mariodiniz如何使用?我试图使用它,但浏览器没有绘制像素…为什么
(()=>{…})()
?如果您不需要读取像素,则不要使用
getImageData
,而是使用
createImageData
。此外,回答此问题时要包含的一个重要点是
setInterval(f,1)
带有一个沉重的
f
是对崩溃的一种呼唤。我不认为
ImageData.data.fill
有什么意义,当我们已经有了
fillRect
时(除非是为了避免在非四舍五入坐标处绘制时出现抗锯齿效果?然后就四舍五入坐标)@Kaiido
Fill
是一个一维函数,有两个剪裁边界,没有合成,在大多数机器上,这将由blit执行,
fillRect
是二维函数,使用当前的合成操作有4个或更多剪裁边界。代码中没有错误,只是逻辑/时序缺陷。问题是很明显,如果你有一个更快速的方法来设置随机访问的像素和一个精确的RGBA值,请告诉我们。我确信OP知道get和create之间的区别,但是请告诉我们为什么不应该使用
getImageData
Hum什么?你的
Fill
不仅仅是
数组。Fill
,它是
Array.flll
+
putImageData
我想putImageData的复杂性取决于每个实现,但我确信它根本不是一维函数。而且,我非常确定这是OP第一次听说ImageData,所以他几乎不可能知道create和get之间的区别,这在性能方面也是巨大的(一)避免所有数据的读取+不乘法,甚至只填充FrReCt和Aray.填充(例如,设置背景,然后一些唯一像素)在我的机器上花费大约相同的时间(FiReCter在我的FF中有点快)考虑函数<代码> StEngScript(像素)其中像素是数组和<代码> {x,y,abg}
其中
ABGR
为int32,
x
y
为随机像素坐标。
y
为随机像素坐标。对于小尺寸像素阵列和大尺寸图像,您将使用直接渲染,对于所有其他情况,您将直接写入图像数据。OP显示的等效像素阵列等于图像像素计数,直接写入像素data在小于1的情况下变得有效,如在
1>(最优=像素.length/(Image.width*Image.height))
中,对于较小的图像,未知值
optimal
较小。由于问题是解绑
 ctx.putImageData(pixelData,0,0);