【问题标题】:Pure Javascript rAF (requestAnimationFrame) - how to update screen at highest available framerate?Pure Javascript rAF (requestAnimationFrame) - 如何以最高可用帧率更新屏幕?
【发布时间】:2020-06-03 09:53:41
【问题描述】:

我正在学习 JavaScript,拥有八年的 Python 经验,作为练习,我制作了一个 Mandelbrot 渲染器,它生成分形并使用 putImageData 一次从左到右更新画布一个单像素列.

我发现通过这种方法,浏览器中的可见图像仅在全屏计算完成时才会更新(而不是像我想要的那样从左到右逐渐显示)。我知道这是预期的行为,所以我决定使用requestAnimationFrame 添加“扫描线”动画。 (就像在这里看到的东西:Christian Stigen Larsen renderer

我的期望是,较轻的计算应该渲染得更快(因为下一帧更快可用),而更高迭代的计算应该渲染得更慢。我发现我的实现是扫描线一直很慢。

我已将此问题与我的 Mandelbrot 计算无关,因为这种行为也发生在以下最小情况下。我在 Chrome 83 上运行它,看到画布从左到右以恒定速率(大约每秒 30 像素)非常缓慢地填充。

我对 rAF 的实施是错误的还是我的期望是错误的?我链接到的渲染器使用setTimeout() 来制作动画,但我读到现在这种做法被广泛劝阻。

我应该如何以可用的最高帧速率对我的画布进行从左到右的扫描更新(我现在不担心限制它)?

编辑: 为清楚起见,下面的代码在 rAF 的每个帧请求处绘制一个细长的矩形,并且花费完全相同相同的时间来绘制整个画布作为 100 次迭代的 Mandelbrot 渲染。

这表明它的缓慢不是由于帧之间发生的计算量。

const canvas = document.querySelector('.myCanvas');
const width =  window.innerWidth;
const height = window.innerHeight;
const ctx = canvas.getContext('2d');

function anim(timestamp, i) {
  if (i < width) {
    ctx.fillRect(i, 0, 1, height);
    window.requestAnimationFrame(function(timestamp) {
      anim(timestamp, i + 1);
    })
  }
}

ctx.fillStyle = 'rgb(0,0,0)';
window.requestAnimationFrame(function(timestamp) {
  anim(timestamp, 0);
});
<!DOCTYPE html>
<html lang="en">

<head>
  <canvas class="myCanvas">
        <p>Add suitable fallback here.</p>
    </canvas>
  <script src="slow%20rAF.js"></script>
  <style>
    body {
      margin: 0;
      overflow: hidden;
    }
  </style>
  <meta charset="UTF-8">
  <title>Mandelbrot</title>
</head>

<body>




</body>


</html>

【问题讨论】:

    标签: javascript requestanimationframe


    【解决方案1】:

    没有“更快”的 requestAnimationFrame。

    一般来说,这个问题的答案是将计算与渲染分开。理想情况下,计算发生在主线程之外,渲染在主线程上处理。即使没有线程,您也应该能够找到一种在 RAF 之外进行计算的方法,并且只需让 RAF 渲染像素。

    【讨论】:

    • 谢谢你,我怀疑在我的调查中。在问题中,我概述了我已将这种行为与任何 mandelbrot 计算隔离开来。但是,即使在我提供的没有进行计算的最小示例中,rAF 也是“慢”的:它只是在每一帧绘制像素宽的矩形。事实上,我发现在每一帧绘制单个矩形的速度与在相同大小的像素切片上执行 100 次迭代 mandelbrot 渲染完全相同。对我来说,这感觉不对。
    • @KIO,您每帧都增加一个像素。 requestAnimationFrame 循环将在 Chrome 中以屏幕刷新率运行,在 FF 中以 60Hz 运行。如果您的显示器是 60Hz 显示器(这很常见),那么在您的 sn-p 中完全填充画布将需要 至少 4980 毫秒。 ( 300px * (1px * (1000/60)) Graham 在解决该问题的方法中也是正确的,我只想指出,即使在并行线程中运行,您仍然应该分批运行它以便它可以需要时对 rAF 回调做出反应。见stackoverflow.com/q/54478195
    • @Kaiido,谢谢。我看到了我的问题 - 这是因为我每帧做了一个像素增量。我没有正确地做数学。我在问题中包含的 sn-p 似乎是 300px 宽,我的显示器是 144Hz,所以用它扫描画布大约需要 2 秒。我应该已经发现了。您关于分离线程的建议是有效的,我会对其进行调查,目前由于我设置增量的方式而导致刷新率出现瓶颈,这就是我要解决的问题。谢谢!
    • @Kaiido,mandelbrot 渲染器无论如何都是分批运行的。如,每个像素值完全独立于相邻像素 - 我目前的方法是一次计算一个条带并以这种方式更新画布。总有一些像素可供 rAF 绘制。
    猜你喜欢
    • 1970-01-01
    • 2022-09-01
    • 2012-07-02
    • 2015-04-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-07-25
    • 1970-01-01
    相关资源
    最近更新 更多