【问题标题】:html5 canvas large sprite sheet image animation performance optimizationhtml5 canvas大sprite sheet图片动画性能优化
【发布时间】:2020-03-22 05:22:17
【问题描述】:

我使用的方法来自 http://www.williammalone.com/articles/create-html5-canvas-javascript-sprite-animation/ 在画布上渲染精灵表动画

而且大部分情况下都可以正常工作

但是当精灵表图像,(在我的例子中是 30000*500,60 帧 png 文件)时,性能非常糟糕,尤其是在 Android webview 上。

我认为图片资源占用了太多内存,但是如何优化它的内存使用呢?我已经尝试通过“ImageOptim”压缩图像,但它没有产生任何明显的差异。

在画布上渲染大型精灵表时,有人可以给我一些关于性能优化的建议吗?

【问题讨论】:

    标签: animation canvas html5-canvas sprite-sheet


    【解决方案1】:

    使用ImageBitmaps

    您的图像可能太大而无法保存在图形卡内存中,这意味着每次都必须再次将其移动到那里,这确实会使事情变得非常缓慢。

    ImageBitmap 对象允许保留原始位图数据以供 GPU 使用,无需额外。
    因此,在初始化时,您将准备好 ImageBitmaps 并丢弃完整的图像。 现在只有准备好放置的小位图会被传递到 GPU。

    async function initSprites( img, sprite_width = img.width, sprite_height = img.height ) {
      // you would have to make the sprite factory logic based on your actual spritesheet,
      // here Im using a simple fixed-size grid from wikimedia
      const sprites = [];
      for( let y = 0; y < img.height; y += sprite_height) {
        for( let x = 0; x < img.width; x += sprite_width ) {
          sprites.push(
            await createImageBitmap( img, x, y, sprite_width, sprite_height )
          );
        }
      }
      return sprites;
    }
    async function loadImage( url ) {
      var img = new Image();
      img.crossOrigin = 'anonymous';
      await new Promise( (res, rej) => {
        img.onload = (e) => res( img );
        img.onerror = rej;
        img.src = url;
      } );
      return img;
    }
    
    async function init() {
      const url = "https://upload.wikimedia.org/wikipedia/commons/b/be/SpriteSheet.png";
      const FPS = 10;
      const sprite_width = 132;
      const sprite_height = 97;
      
      // we don't keep any reference to the Image
      const sprites = await initSprites( await loadImage( url ), sprite_width, sprite_height );
      
      const canvas = document.getElementById( 'canvas' );
      const ctx = canvas.getContext( '2d' );
      const frame_time = 1000 / FPS;
      let sprite_index = 0;
      let lastTime = performance.now();
      
      requestAnimationFrame( update );
      
      function update( t ) {
        if( t - lastTime > frame_time ) {
          lastTime = t;
          sprite_index = (sprite_index + 1) % sprites.length;
          draw();
        }
        requestAnimationFrame( update );
      }
      
      function draw() {
        ctx.clearRect( 0, 0, canvas.width, canvas.height );
        // we just reproduce the original spritesheet
        // but animated
        let inner_index = 0;
        for(let y = 0; y < 3; y++) {
          for( let x = 0; x < 4; x ++ ) {
            inner_index ++;
            const index = (sprite_index + inner_index) % sprites.length;
            const sprite = sprites[ index ];
            ctx.drawImage( sprite, x * sprite_width, y * sprite_height );
          }
        }
      }
    }
    
    // for Safari and IE
    monkeyPatchCreateImageBitmap();
    
    init().catch( console.error );
    
    
    // a very poor monkey patch, only allowing HTMLImageElement as source
    // returns an HTMLCanvasElement
    function monkeyPatchCreateImageBitmap() {
      if( typeof window.createImageBitmap === 'undefined' ) {
        window.createImageBitmap = monkeyPatch;
      }
      function monkeyPatch( img, sx = 0 , sy = 0, sw = img.width, sh = img.height ){
        const canvas = document.createElement( 'canvas' );
        canvas.width = sw;
        canvas.height = sh;
        canvas.getContext( '2d' )
          .drawImage( img, sx, sy, sw, sh, 0, 0, sw, sh );
        canvas.close = (e) => canvas.width = 0;
        return Promise.resolve( canvas );
      };
    }
    &lt;canvas id="canvas" width="528" height="291"&gt;&lt;/canvas&gt;

    【讨论】:

    • 我的问题是sprite sheet图片过大的时候,会占用太多内存,导致动画看起来卡顿,有没有一些内存优化的练习?
    • 即使使用 ImageBitmaps?之后,您的图像数据应该会被释放。此外,请确保只初始化您实际使用的精灵,例如,如果您制作多关卡游戏,则无需在 lvl1 加载 lvl99 老板。然后,可以使动画滞后的是移动内存中的数据,这就是这个答案的重点。大量内存被使用本身不应该导致滞后。但是,用于资产的内存越多,可用于逻辑的内存就越少,因此请务必在那里进行优化。最后,进一步优化资产的唯一方法是减小它们的大小。
    猜你喜欢
    • 2012-06-26
    • 2014-10-03
    • 2014-02-02
    • 1970-01-01
    • 1970-01-01
    • 2012-09-16
    • 1970-01-01
    • 2015-02-21
    • 1970-01-01
    相关资源
    最近更新 更多