HTML5 Canvas:使用drawImage绘制/缓存的元素在缩放和/或移动时会变得平滑

发布于 2024-12-20 02:31:01 字数 2680 浏览 2 评论 0原文

我确实知道drawImagexy的浮点/整数值的情况。但我需要的是一个能够缓存形状的流畅动画。

例如,我想画一些复杂的形状(即SVG-tiger,转换为 canvas-commands) 到画布一次,然后使用 ctx.translate 和 ctx.drawImage 平滑移动它。然后我需要浮点值,因为我需要逐步移动:

这是 JSFiddle 的示例:

  • :速度快,将Math.floor应用于translate参数(xy是等于以秒为单位的时间乘以10):动画很奇怪(连续的,不平滑)。
  • :速度较慢,Math.floor应用于翻译参数(xy等于以秒为单位的时间):动画很奇怪(连续的,不平滑)。
  • :速度快,无舍入,浮点值(x 和 < code>y 等于以秒为单位的时间乘以 10)。速度很快,所以动画看起来不错。
  • :速度慢,无舍入,浮点值(xy 等于时间(以秒为单位)。速度很慢,因此动画看起来脉动为什么?

最后一个案例让我感到困惑。我的尝试是错的吗?有可能让这个缓存技巧发挥作用吗?

在 Firefox 中,画布有一个名为 mozImageSmoothingEnabled 的属性(参见),但在其他浏览器中没有任何帮助。它还消除了路径平滑。

代码摘录:

var shapeCanvas = null;
var w = 320, h = 240;
var startTime = 0;

function start() {
    startTime = Date.now();
    var docCanvas = document.getElementById('canvas');
    . . .
    shapeCanvas = document.createElement('canvas');
    . . .
    drawShape(shapeCanvas.getContext('2d'));

    drawNext(docCanvas.getContext('2d'));
}

function drawNext(ctx) {
    var msec = (Date.now() - startTime);
    var time = msec / 1000; // seconds passed from start
    ctx.clearRect(0, 0, w, h);

    ctx.save();
    // the lines to change: time | (time * 10) | Math.floor(time * 10)
    ctx.translate((time < 500) ? Math.floor(time * 10) : 500,
                  (time < 500) ? Math.floor(time * 10) : 500);
    ctx.drawImage(shapeCanvas, 0, 0);
    ctx.restore();

    __nextFrame(function() {
       drawNext(ctx);
    });
}

function drawShape(ctx) {
    . . .
}

I do know about the case of float/integer values for drawImage's x and y. But what I need is a smooth animation with an ability to cache my shapes.

For example, I want to draw some complex shape (i.e. SVG-tiger, converted to canvas-commands) to canvas just once and then move it smoothly with ctx.translate and ctx.drawImage. I need the float values then, because instead I get a step-by-step moving:

Here's the examples at JSFiddle:

  • One: Fast speed, with Math.floor applied to translate parameters (x and y are equal to time in seconds multiplied by 10): Animation is weird (sequential, not smooth).
  • Two: Slow speed, with Math.floor applied to translate parameters (x and y are equal to time in seconds): Animation is weird (sequential, not smooth).
  • Three: Fast speed, no rounding, float values (x and y are equal to time in seconds multiplied by 10). Speed is fast, so animation looks good.
  • Four: Slow speed, no rounding, float values (x and y are equal to time in seconds). Speed is slow, so animation looks pulsating. Why?

The last case is the one that confuses me. Am I wrong in my tryings and there is a possibility to make this caching trick work nice?

In Firefox, there is a property of canvas named mozImageSmoothingEnabled (see), but there is no help from that in other browsers. And it also removes paths smoothing.

Code extract:

var shapeCanvas = null;
var w = 320, h = 240;
var startTime = 0;

function start() {
    startTime = Date.now();
    var docCanvas = document.getElementById('canvas');
    . . .
    shapeCanvas = document.createElement('canvas');
    . . .
    drawShape(shapeCanvas.getContext('2d'));

    drawNext(docCanvas.getContext('2d'));
}

function drawNext(ctx) {
    var msec = (Date.now() - startTime);
    var time = msec / 1000; // seconds passed from start
    ctx.clearRect(0, 0, w, h);

    ctx.save();
    // the lines to change: time | (time * 10) | Math.floor(time * 10)
    ctx.translate((time < 500) ? Math.floor(time * 10) : 500,
                  (time < 500) ? Math.floor(time * 10) : 500);
    ctx.drawImage(shapeCanvas, 0, 0);
    ctx.restore();

    __nextFrame(function() {
       drawNext(ctx);
    });
}

function drawShape(ctx) {
    . . .
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

蔚蓝源自深海 2024-12-27 02:31:01

我在你的第一个链接中写了教程。

只是澄清一下:

shapeCanvas.style.width = w + 'px';
shapeCanvas.style.height = h + 'px';

这并不值得做。如果它只是一个内存中的画布,那么设置样式是没有意义的,而且你也不应该真正想要设置画布的宽度和高度 style ,它只会让事情变得混乱。

埃利斯本在评论中所说的几乎就是正在发生的事情。

我敢打赌,可以通过一些黑客的方式来绕过它。一种方法可能是确保它永远不会绘制在整数像素上。另一种可能是在绘制任何内容之前使用 ctx.scale(.99,.99) ,以便它始终是抗锯齿的。在这里很难得到一致的解决方案,因为不同的浏览器的抗锯齿实现是不同的。

以下是我自己的一些实验:

http://jsfiddle.net/KYZYT/29/

第一个两个是从画布绘制的形状,也是从 PNG 绘制的形状。

第二个是同一对,但按 .99,.99 缩放。

最后一个是真实的。它仍然有点模糊,但看起来比使用图像清晰得多。

我的所有实验都不会导致你的脉动结束,至少在微观层面上是这样。我认为如果您想将像素完美的图像动画到半像素空间上,这就是您必须忍受的事情。

如果您真的觉得自己不能只在完美的像素上绘制,那么为了保持一致性,您的(第二)最佳选择可能是找到一种始终强制消除锯齿的方法。确保始终将其转换为非整数或稍微缩放它是不错的选择,但可能还有其他选择。

老实说,最好的办法是不要缓存这些动画路径,除非您绝对需要它们的性能。缓存您制作的风格化按钮和其他静态内容,但如果您有动画路径需要缓慢而精确地移动并且看起来非常好,那么您最好坚持使用真实的内容而不是我的缓存优化,除非您真的 那些也需要它。

I wrote the tutorial in your first link.

Just to clear the air:

shapeCanvas.style.width = w + 'px';
shapeCanvas.style.height = h + 'px';

is not really worth doing. No point setting the style if its just a in-memory canvas, and you shouldn't really ever want to set the width and height style of a canvas anyway, it just confounds things.

What ellisbben said in the comment is pretty much what's happening.

It's possible to get around it in a few hackish ways I bet. One way might be to make sure its never drawn on an integer pixel. Another might be to use ctx.scale(.99,.99) before drawing anything so it is always anti-aliased. It's tough to get a consistent solution here because different browswer's implementations of anti-aliasing are different.

Here are a few experiments from myself:

http://jsfiddle.net/KYZYT/29/

The first two are the shape drawn from a canvas and also drawn from a PNG

The second two are the same pair but scaled by .99,.99

The last one is the real thing. It still blurs a bit but looks a lot sharper than using the images.

None of my experiments lead to an end of your pulsating, at least not on a microscopic level. I think this is just something you're going to have to live with if you want to animate pixel-perfect images onto half-pixel spaces.

If you really feel you can't just draw on perfect pixels then your (second) best bet for consistency is probably to find a way to force anti-aliasing at all times. Making sure you are always translated to a non-integer or scaling it ever so slightly are decent candidates, but there may be others.

To be honest, you best bet is to not cache these animated paths until you absolutely need the performance from them. Cache the stylized buttons and other static things you make, but if you've got animated paths that need to move slowly and precisely and look very good, you might as well stick with the true thing over my caching optimization unless you really need it for those too.

哆兒滾 2024-12-27 02:31:01

有点无耻的插件,但是:我已经用有点 hacky 的方式在 HTML5 老虎机游戏中实现了流畅的动画。生成的缓存图像在小画布上绘制一次,然后我使用带有 -moz-transform / -webkit-transform 样式的 translate3d() 来让画布移动、镜像和缩放图像。

预生成

  1. 创建图像
  2. 绘制图像内容
  3. 创建画布对象

在 DOM动画阶段

  1. 清除画布
  2. 将缓存的图像绘制到画布上
  3. 使用 CSS3 变换(scale3d 和 translate3d)来移动画布。

Bit shameless plug but: I've implement smooth animation in HTML5 slot game with bit hacky way. The generated cached Image is drawn on small canvas once and then I used translate3d() with -moz-transform / -webkit-transform styles for the canvas to move, mirror and scale the image around.

Pregeneration

  1. Create Image
  2. Draw image content
  3. Create canvas object in DOM

Animation phase

  1. Clear canvas
  2. Draw the cached image to the canvas
  3. Use CSS3 transforms (scale3d and translate3d) to move canvas around.
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文