Анимация текстур в WebGL
В этой демонстрации мы развиваем предыдущий пример, заменив статичные текстуры кадрами воспроизводимого файла видео mp4. Это довольно просто и интересно, поэтому давайте начнём. Вы можете использовать похожий код для использования любого типа данных (например, <canvas>) в качестве источника для ваших текстур.
Получение доступа к видео
Первый шаг — создать элемент <video>, который мы будем использовать для извлечения кадров видео.
Примечание: Добавьте эту декларацию в начало скрипта "webgl-demo.js":
// will set to true when video can be copied to texture let copyVideo = false;
Примечание: Добавьте эту функцию в ваш скрипт "webgl-demo.js":
function setupVideo(url) {
const video = document.createElement("video");
let playing = false;
let timeupdate = false;
video.playsInline = true;
video.muted = true;
video.loop = true;
// Waiting for these 2 events ensures
// there is data in the video
video.addEventListener(
"playing",
() => {
playing = true;
checkReady();
},
true,
);
video.addEventListener(
"timeupdate",
() => {
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 для начала загрузки и воспроизведения видео.
Видео должно загружаться из защищённого источника, чтобы использовать его для предоставления данных текстуры для WebGL. Это означает, что вам нужно не только развернуть код, используя защищённый веб-сервер, но и защищённый сервер для тестирования. Обратитесь к Как настроить локальный тестовый сервер? для получения помощи.
Использование кадров видео в качестве текстуры
Следующее изменение — инициализация текстуры, которая становится намного проще, так как нам больше не нужно загружать файл изображения. Вместо этого мы создаём пустой объект текстуры, помещаем в него один пиксель и устанавливаем его фильтрацию для последующего использования.
Примечание: Замените функцию loadTexture() в "webgl-demo.js" следующим кодом:
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;
}
Примечание: Добавьте следующую функцию в "webgl-demo.js":
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,
);
}
Вы уже видели этот код. Он почти идентичен функции onload изображения в предыдущем примере — за исключением того, что при вызове texImage2D(), вместо передачи объекта Image, мы передаём элемент <video>. WebGL знает, как извлечь текущий кадр и использовать его в качестве текстуры.
Далее, нам нужно вызвать эти новые функции из нашей функции main().
Примечание: В вашей функции main() замените вызов loadTexture() этим кодом:
const texture = initTexture(gl);
const video = setupVideo("Firefox.mp4");
Примечание: Вам также необходимо загрузить файл Firefox.mp4 в ту же папку, что и файлы JavaScript.
Примечание: В вашей функции main() замените функцию render() на эту:
// Draw the scene repeatedly
function render(now) {
now *= 0.001; // convert to seconds
deltaTime = now - then;
then = now;
if (copyVideo) {
updateTexture(gl, texture, video);
}
drawScene(gl, programInfo, buffers, texture, cubeRotation);
cubeRotation += deltaTime;
requestAnimationFrame(render);
}
Если copyVideo имеет значение true, мы вызываем updateTexture() сразу перед вызовом функции drawScene().
Вот и всё!
Посмотреть весь код | Открыть эту демонстрацию в новой вкладке
См. также
© 2005–2024 MDN contributors.
Licensed under the Creative Commons Attribution-ShareAlike License v2.5 or later.
https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API/Tutorial/Animating_textures_in_WebGL