动画纹理 - Web API 接口参考 编辑
在本演示中,我们以上一个示例为基础,将静态纹理替换为正在播放的mp4视频文件的帧。实际上,这很容易做到,而且观看起来很有趣,所以让我们开始吧。您可以使用类似的代码来使用任何类型的数据(例如<canvas>
) 作为纹理的源。
获取视频
第一步是创建<video>
将用于检索视频帧的元素:
// will set to true when video can be copied to texture
var copyVideo = false;
function setupVideo(url) {
const video = document.createElement('video');
var playing = false;
var timeupdate = false;
video.autoplay = true;
video.muted = true;
video.loop = true;
// Waiting for these 2 events ensures
// there is data in the video
video.addEventListener('playing', function() {
playing = true;
checkReady();
}, true);
video.addEventListener('timeupdate', function() {
timeupdate = true;
checkReady();
}, true);
video.src = url;
video.play();
function checkReady() {
if (playing && timeupdate) {
copyVideo = true;
}
}
return video;
}
首先,我们创建一个视频元素。我们将其设置为自动播放,静音和循环播放视频。然后,我们设置了两个事件以确保视频正在播放并且时间轴已更新。我们需要进行这两项检查,因为如果将视频上传到WebGL尚无可用数据,它将产生错误。检查这两个事件可确保有可用数据,并且可以安全地开始将视频上传到WebGL纹理。在上面的代码中,我们确认是否同时发生了这两个事件。如果是这样,我们将全局变量设置 copyVideo
为true,以表示可以安全地开始将视频复制到纹理。
最后,我们将src
属性设置为start并调用play
以开始加载和播放视频。
用视频帧作为纹理
接下来的更改是initTexture()
,它变得更加简单,因为它不再需要加载图像文件。相反,它所做的只是创建一个空的纹理对象,在其中放置一个像素,然后设置其过滤条件供以后使用:
function initTexture(gl) {
const texture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, texture);
// Because video has to be download over the internet
// they might take a moment until it's ready so
// put a single pixel in the texture so we can
// use it immediately.
const level = 0;
const internalFormat = gl.RGBA;
const width = 1;
const height = 1;
const border = 0;
const srcFormat = gl.RGBA;
const srcType = gl.UNSIGNED_BYTE;
const pixel = new Uint8Array([0, 0, 255, 255]); // opaque blue
gl.texImage2D(gl.TEXTURE_2D, level, internalFormat,
width, height, border, srcFormat, srcType,
pixel);
// Turn off mips and set wrapping to clamp to edge so it
// will work regardless of the dimensions of the video.
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);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
return texture;
}
这里是updateTexture()
方法; 这是完成实际工作的地方:function updateTexture(gl, texture, video) {
const level = 0;
const internalFormat = gl.RGBA;
const srcFormat = gl.RGBA;
const srcType = gl.UNSIGNED_BYTE;
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.texImage2D(gl.TEXTURE_2D, level, internalFormat,
srcFormat, srcType, video);
}
您之前已经看过此代码。它与上一个示例中的image onload函数几乎相同-除非我们调用texImage2D()
,而不是传递Image
对象,而是传递<video>
元素。WebGL知道如何拉出当前帧并将其用作纹理。
然后,在main()
代替通话,以loadTexture()
在前面的例子中,我们调用 initTexture
()
之后setupVideo()
。
在render()
if是否copyVideo
为真的定义中,则 updateTexture()
每次调用drawScene()
函数之前都会调用一次 。
const texture = initTexture(gl);
const video = setupVideo('Firefox.mp4');
var then = 0;
// Draw the scene repeatedly
function render(now) {
now *= 0.001; // convert to seconds
const deltaTime = now - then;
then = now;
if (copyVideo) {
updateTexture(gl, texture, video);
}
drawScene(gl, programInfo, buffers, texture, deltaTime);
requestAnimationFrame(render);
}
requestAnimationFrame(render);
下面是结果:
参考
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论