动画纹理

这篇翻译不完整。请帮忙从英语翻译这篇文章

在本篇介绍中,我们基于上一个例子编译构建,用播放 Ogg 视频文件的帧来替换我们静态的纹理。这实际上很简单,但是看起来很有趣,所以我们开始吧。类似的代码可以是任何近似的数据 (例如 <canvas>)作为我们纹理的资源。

获取视频

第一步是创建一个 <video> 元素, 我们将从这个元素获取视频帧:

<video id="video">
  Your browser doesn't appear to support the HTML5 <code>&lt;video&gt;</code> element.
</video>

这里简单的创建一个元素来播放视频文件 "Firefox.ogv",我们使用CSS将这个video元素隐藏。

video {
  display: none;
}

接着我们将注意力转到Javascript代码上,通过对 start() 函数添加一行获取video元素的代码开始:

videoElement = document.getElementById('video');

然后 we replace the code that set up the interval-driven calls to drawScene() with this:

videoElement.addEventListener('canplaythrough', startVideo, true);
videoElement.addEventListener('ended', videoDone, true);

最后我们给video元素设置src属性让它开始加载。

video.preload = 'auto';
videoElement.src = 'Firefox.ogv';

The idea here is that we don't want to start the animation until enough of the video has been buffered that it can be played without interruption. So we add an event listener to wait for the video element to tell us that it's buffered enough data that it believes the entire video can be played without pausing.

The startVideo() function looks like this:

function startVideo() {
  videoElement.play();
  intervalID = setInterval(drawScene, 15);
}

This simply starts playing the video, then establishes the interval-driven calls to drawScene() to handle rendering the cube.

We also add a second event listener on the video's "ended" event so that when the video is finished playing, we can stop the animation, since otherwise it's just chewing up processor time for no good reason.

function videoDone() {
  clearInterval(intervalID);
}

The videoDone() function simply calls window.clearInterval() to end the calls to update the animation.

Using the video frames as a texture

The next change is to initTexture(), which becomes much simpler, since it no longer needs to load an image file. Instead, all it does is create an empty texture object and set its filtering for later use:

function initTextures() {
  cubeTexture = gl.createTexture();
  gl.bindTexture(gl.TEXTURE_2D, cubeTexture);
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
}
Here's what the updateTexture() function looks like; this is where the real work is done:
function updateTexture() {
  gl.bindTexture(gl.TEXTURE_2D, cubeTexture);
  gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
  gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA,
        gl.UNSIGNED_BYTE, videoElement);
}

You've seen this code before. It's nearly identical to the handleTextureLoaded() routine in the previous example, except when we call texImage2D(), instead of passing an Image object, we pass in the <video> element. WebGL knows how to pull the current frame out and use it as a texture.

updateTexture() is called each time we're ready to redraw our scene, by the drawScene() function, to which the only change is adding a call to updateTexture() before doing anything else.

That's all there is to it!

View the complete code | Open this demo on a new page

See also

文档标签和贡献者

 此页面的贡献者: liuzheng644607, Gaohaoyang
 最后编辑者: liuzheng644607,