【问题标题】:What is the best way to show an animation using images as frames?使用图像作为框架显示动画的最佳方式是什么?
【发布时间】:2014-06-07 05:57:09
【问题描述】:

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

就我而言,有两种选择:

  • 更改图片标签的src标签
  • <canvas> 中显示图像,如here 所述

在为所有浏览器编写复杂的基准测试之前,我想问问有经验的人:

  1. 最好的方法是什么?
  2. 这些方法或加快速度的方法是否存在任何缺陷?

【问题讨论】:

  • 取决于动画元素的尺寸、帧数、是否关心时间以及是否需要音频之类的东西来播放。您需要的详细信息是什么?为什么不是视频标签?
  • 你在 60 fps 时会遇到麻烦。大多数浏览器都锁定为 30 fps。
  • 你可以在canvas元素中设置每n毫秒绘制一帧的间隔
  • @NatZimmermann 你从哪里听到的?我的上一份合同要求我使用 W3C 网络技术来运行带有 DOM 动画的全动态视频和交互式游戏,而流畅的性能至关重要。我们在 Chrome 31、IE10 或同时代的 Firefox 版本上没有发现此问题。
  • @Barney 抱歉,我累了 - 我以为他们被锁定到 30,但实际上他们被锁定到 60。对不起!

标签: javascript html performance canvas gpu


【解决方案1】:

您想要的解决方案是画布。
只有有了它,您才能(轻松)使用一个或一组简化的图形文件来制作动画。
由于您负担不起要下载一千个文件,您实际上需要处理打包文件,这可能看起来像:

这样的文件可以包含几个字符或任何图形。

加载图像后,您必须计算每一帧的纹理坐标。
动画是一系列帧。
这里画布的关键方法是 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);
}

【讨论】:

  • jsFiddle 是赢家!你从哪里弄到这只鸟的?
  • 确实 jsfiddle 摇滚!我用我们亲爱的朋友谷歌图片('sprite animation')找到了这张图片:-)
【解决方案2】:

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

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

【讨论】:

    【解决方案3】:

    使用类似的东西:

    // 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 帧,但播放速度不会太快或太慢。

    【讨论】:

    • 非常感谢您的回答,Hamza。我没有想到使用requestAnimationFrame 的想法。但我问的是输出图像的方式:画布或图像标签。
    • 好吧,如果图像都是相同的尺寸,我会预先加载它们,看看在单个可见图像上更改src 标记时它的性能如何。如果尺寸不是很大(任何一个尺寸都超过 512 像素),我认为这就足够了。图像的尺寸在这里有很大的不同。
    • 另外,如果您在网站上的其他元素上制作 DOM 动画等,这可能会减慢速度……在这种情况下,您希望在那里达到最佳状态。你可能想看看greensock.com/gsap-js
    【解决方案4】:

    我会将所有图像与position:absolute; 放在一个div 中,然后使用jQuery each 函数顺序隐藏图像。

    【讨论】:

    • 我不认为图像会在循环完成之前放置介词。因此只看到 2 张图片
    猜你喜欢
    • 2011-05-20
    • 1970-01-01
    • 2012-01-10
    • 1970-01-01
    • 2016-06-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-16
    相关资源
    最近更新 更多