使用图像作为帧显示动画的最佳方法是什么?

时间:2014-04-22 17:47:02

标签: javascript html5 performance canvas gpu

我打算通过一个接一个地快速显示几个图像来播放短动画。图像将是动画的帧。我想要60 fps。当然,图像将被预加载。我有一些理由不想使用<video>标记。

至于我,有两个选择:

  • 更改图片代码的src代码
  • here
  • 所述,在<canvas>内显示图片

在为所有浏览器编写复杂的基准之前,我会问那些有经验的人:

  1. 哪种方法最好?
  2. 这些方法或方法是否有任何陷阱加速?

4 个答案:

答案 0 :(得分:2)

我建议您按照第二个选项中的建议在画布中显示图像。这样做的原因是,虽然您可以确保在DOM中预先加载图像,但是无法控制何时将它们从源解码为图像数据 - 通常这将在文档中显示它们时发生,这可以(并且确实!)导致执行延迟,这将影响您的帧速率。使用画布,您还可以预先解码图像数据,从而产生更流畅的动画。

我最近使用他的技术,当我为信息亭写的一些幻灯片式软件在预先加载的图像滑入视图时显示帧速率(60 FPS到20 FPS)的令人讨厌的下降:使用Chrome的开发工具的时间轴功能I was able to isolate the image decoding step as locking UI for 50-100 milliseconds,我设法通过使用画布提前解码图像来完全避免这种情况。

答案 1 :(得分:1)

您想要的解决方案是画布 只有使用它,您才能(轻松)使用一个 - 或者一组简化的图形文件,您将用于动画。
由于您无法承载下载数千个文件,因此您实际上需要处理打包文件,这可能看起来像:

enter image description here

可以在此类文件中打包多个字符或任何图形。

加载图像后,必须计算每帧的纹理坐标 动画是一系列帧 这里画布的关键方法是drawImage,它有一个9参数风格,允许剪辑/调整大小/ ...图像。

我做了一个小小的演示,但你应该认真考虑使用动画框架,它可能会为你提供最有价值的工具(动画转换,引用一个)。

在这里摆弄:http://jsfiddle.net/gamealchemist/Vn2Nt/

// array containig texture coords of all frames.
var textureCoords = [];

// fill the textureCoords using image img, assuming
//   frames are tiled in a 'regular way', sized tw X th, 
//   uses only cnt frames.
function fillTextureCoords(img, tw, th, cnt) {
    var w = img.width,
        h = img.height;
    var hCount = Math.floor(w / tw),
        vCount = Math.floor(h / th);
    for (var vIndex = 0; vIndex < vCount; vIndex++)
    for (var hIndex = 0; hIndex < hCount; hIndex++) {
        textureCoords.push({
            u: hIndex * tw,
            v: vIndex * th,
            w: tw,
            h: th
        });
        cnt--;
        if (!cnt) return;
    }
}

// frames of the animation. 
// Contains index to the textureCoords array.
var frames = [];

for (var i = 0; i < 14; i++) frames.push(i);

// duration of a single frame.
var frameDuration = 150;

// current time of the animation (ms).
var animationStatus = 0;

// draws at (0,0) the current animation frame
function drawThatFrame() {
    var whichFrame = Math.floor(animationStatus / frameDuration);
    whichFrame %= frames.length;
    var tCoord = textureCoords[frames[whichFrame]];
    context.drawImage(myBird, tCoord.u, tCoord.v, tCoord.w, tCoord.h, 0, 0, tCoord.w, tCoord.h);
}

答案 2 :(得分:0)

我会在div中使用position:absolute;将所有图像放在彼此的顶部,然后使用jQuery每个函数按顺序隐藏图像。

答案 3 :(得分:0)

使用类似:

// this is a useful shim for requestAnimationFrame. I copied it from somewhere else:
window.requestAnimFrame = function(){
    return (
        window.requestAnimationFrame       ||
        window.webkitRequestAnimationFrame ||
        window.mozRequestAnimationFrame    ||
        window.oRequestAnimationFrame      ||
        window.msRequestAnimationFrame     ||
        function(/* function */ callback){
            window.setTimeout(callback, 1000 / 60);
        }
    );
}();

var currentFrameTime, previousFrameTime, timeBetweenFrames;
var playbackStartTime = Date.now();
var timePerFrame = 1000/60.0;

function updateFrame(frameNumber) {
    requestAnimFrame(updateFrame);

    currentFrameNumber = parseInt((currentFrameTime - playbackStartTime) / timePerFrame);

    showImage(frameNumber);
}

它会显示最高每秒60帧,但不会播放太快或太慢。