Spec-Zone.ru › Web APIs

Анимация текстур в 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().

Вот и всё!

Посмотреть весь код | Открыть эту демонстрацию в новой вкладке

См. также

  • HTML видео и аудио
  • Предыдущая

© 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

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API