Webgl动画纹理性能与画布drawImage性能

时间:2014-11-30 00:28:15

标签: javascript html5 canvas webgl

我正在开始一个项目,我想从单个视频中切片,然后将这些部分重新绘制到屏幕上的不同对象上。我知道我可以通过使用drawImage将视频部分重绘到canvas元素上来实现。在进行研究时,似乎可以在WebGL中使用动画纹理做同样的事情。有没有人知道通过使用WebGL动画纹理来执行此操作而不是drawImage会有任何性能提升?

1 个答案:

答案 0 :(得分:7)

WebGL在2D画布性能方面具有优势,但是,由于您正在处理视频,因此问题是如果使用WebGL有任何意义。

考虑到NTSC世界中的视频很少超过30 FPS(PAL 25 fps),您将有一个很好的时间预算切片视频并重新绘制它们。另外考虑drawImage是一个非常快速的操作并且也有硬件支持(并且没有),你可以通过WebGL来解决这个问题,而WebGL并不适用于所有硬件(如低端消费者和旧硬件) ,并且对它的支持各不相同(在撰写本文时)。

在这种情况下,我最初会坚持使用2D画布。如果您需要将切片包裹并投影到3D对象上,则2D画布不是最佳选择。例如,您可以直接在canvas元素上使用CSS 3D转换来实现某些事物,例如四边形转换。如果需要不同的转换,只需使用不同的canvas元素,每个元素代表一个切片。

这是一个技巧顺便说一下。是创建一个离屏画布,您首先绘制框架。这样,您就不必使用正在运行的视频从元素中获取可能是一项昂贵的操作,具体取决于浏览器获取视频位图数据的方式。

示例:



var ctx = canvas.getContext('2d'),
    sw = 32,
    frame = document.createElement("canvas"), // "frame buffer"
    fctx = frame.getContext("2d");

frame.width = 500;
frame.height = 280;

video.addEventListener("playing", sliceAndDice, false);
function sliceAndDice() {

  fctx.drawImage(video, 0, 0); // video to "frame buffer" to make it more smooth
  
    // some misc slicing
    for(var x = 0; x < frame.width; x += sw) {
        var y = Math.sin(x*1.5) * sw + 20;
        ctx.drawImage(frame, x      , 0, sw, frame.height,   // source slice
                             x * 1.1, y, sw, frame.height);  // dest. slice
    }
    requestAnimationFrame(sliceAndDice);
}
&#13;
<canvas id="canvas" width=560 height=320></canvas>
<video style="display:none" id="video" width="500" height="280" preload="auto" autoplay="true">
  <source src="//clips.vorwaerts-gmbh.de/big_buck_bunny.mp4" type="video/mp4">
  <source src="//clips.vorwaerts-gmbh.de/big_buck_bunny.webm" type="video/webm">
  <source src="//clips.vorwaerts-gmbh.de/big_buck_bunny.ogv" type="video/ogg">
</video>
&#13;
&#13;
&#13;

另一个带有320个切片的演示,可以让你用2D画布将它推得很远:

&#13;
&#13;
var ctx = canvas.getContext('2d'),
    frame = document.createElement("canvas"),         // "frame buffer"
    fctx = frame.getContext("2d"),
    dlt = 0;

frame.width = video.width;
frame.height = video.height;

video.addEventListener("playing", sliceAndDice, false);
function sliceAndDice() {

  fctx.drawImage(video, 0, 0);   // video to frame buffer to make it smoother
  
  // some misc slicing
  for(var x = 0, y; x < frame.width; x++) {
      y = Math.sin(x*32+dlt) * 3 + 10;               // "random" y pos.
      ctx.drawImage(frame, x, 0, 1, frame.height,   // source slice
                           x, y, 1, frame.height);  // dest. slice
  }
  dlt += 0.2;
  requestAnimationFrame(sliceAndDice);
};
&#13;
<canvas id="canvas" width=560 height=320></canvas>
<video style="display:none" id="video" width="500" height="280"
       preload="auto" autoplay="true">
<source src="//clips.vorwaerts-gmbh.de/big_buck_bunny.mp4" type="video/mp4">
<source src="//clips.vorwaerts-gmbh.de/big_buck_bunny.webm"type="video/webm">
<source src="//clips.vorwaerts-gmbh.de/big_buck_bunny.ogv" type="video/ogg">
</video>
&#13;
&#13;
&#13;