HTML Canvas Sniff Webgl Data

Этот вопрос может быть странным, но предположим, что у нас есть холст, который, например, рисует некоторый трехмерный контент, такой как этот эксперимент.

Не принимая во внимание использование ThreeJS, Babylon или любой другой библиотеки для достижения того же эффекта, возможно установить некоторый интервал, который копирует рождение каждого вокселя и повторяет (перерисовывает) его позже.

Просто я хочу записать процесс рисования холста и воспроизвести его без использования RTC, видео или последовательности изображений.

Что сделано?

Я пытался с WebGl Context и Stream Capture, но, к сожалению, не смог достичь желаемого результата.

Может кто-нибудь помочь с этим?

2 ответа

Решение

Вы можете обернуть контекст WebGL и захватить все вызовы функций. Пример переноса контекста WebGL будет выглядеть примерно так:

const rawgl = document.querySelector("canvas").getContext("webgl");
const gl = wrapContext(rawgl);

gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
gl.enable(gl.SCISSOR_TEST);
gl.scissor(40, 50, 200, 60);
gl.clearColor(0,1,1,1);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.scissor(60, 40, 70, 90);
gl.clearColor(1,0,1,1);
gl.clear(gl.COLOR_BUFFER_BIT);

function wrapContext(gl) {
  const wrapper = {};
  for (let name in gl) {
    var prop = gl[name];
    if (typeof(prop) === 'function') {
      wrapper[name] = wrapFunction(gl, name, prop);
    } else {
      wrapProperty(wrapper, gl, name);
    }
  }
  return wrapper;
}

function wrapFunction(gl, name, origFn) {
  // return a function that logs the call and then calls the original func
  return function(...args) {
    log(`gl.${name}(${[...args].join(", ")});`);
    origFn.apply(gl, arguments);
  };
}

function wrapProperty(wrapper, gl, name) {
  // make a getter because these values are dynamic
  Object.defineProperty(wrapper, name, {
    enumerable: true,
    get: function() {
      return gl[name];
    },
  });
}

function log(...args) {
  const elem = document.createElement("pre");
  elem.textContent = [...args].join(" ");
  document.body.appendChild(elem);
}
canvas { border: 1px solid black; }
pre { margin: 0; }
<canvas></canvas>  

В вашем случае вместо регистрации вызовов вы добавляете их в какой-либо массив вызовов только в тех кадрах, которые хотите захватить.

Затем вам нужно каким-то образом отслеживать все ресурсы (буферы, кадровые буферы текстур, рендер-буферы, шейдеры, программы) и все их параметры (например, настройки фильтрации на текстурах), а также отслеживать одинаковые настройки и т. Д.

WebGL-Inspector делает это и может воспроизводить кадры, поэтому это может быть хорошим примером. Там также есть библиотека webgl-capture.

То, что вам нужно захватить для вашей программы, зависит от вашей программы. Например, если вы знаете, что ваши буферы и текстуры никогда не меняются, и они все еще находятся в памяти, когда вы хотите воспроизвести, то, возможно, вам не нужно пытаться захватить состояние буферов и текстур, что должны делать оба приведенных выше примера.

Я не знаю, как ты пробовал с captureStream метод, но на вашей странице примера этот код работает.

let s = mycanvas.captureStream(),
r = new MediaRecorder(s),
chunks = [];
r.ondataavailable = e => chunks.push(e.data);
r.onstop = e => {
  let videoURL = URL.createObjectURL(new Blob(chunks));
  doSomethingWith(videoURL);
  };
r.start();
setTimeout(_=>r.stop(), 3000); // records 3 seconds

Теперь, когда у вас есть действительный blobURL, указывающий на запись вашего холста, вы можете воспроизвести его в <video> элемент, а затем нарисуйте его в своем контексте webgl.

Другие вопросы по тегам