Three.js: текстура в текстуру данных

Я пытаюсь реализовать отложенное средство просмотра веб-камеры в javascript, используя Three.js для возможностей WebGL.

Мне нужно хранить кадры, полученные с веб-камеры, чтобы их можно было показать через некоторое время (от нескольких миллисекунд до нескольких секунд). Я могу сделать это без Three.js, используя canvas и getImageData(). Вы можете найти пример на jsfidle.

Я пытаюсь найти способ сделать это без холста, но с использованием объекта Three.js Texture или DataTexture. Вот пример того, что я пытаюсь сделать. Проблема в том, что я не могу найти, как скопировать изображение из Texture (image имеет тип HTMLVideoElement) в другое.

В функции rotateFrames() старый кадр должен быть потерян, а новый должен заменить его, как в FIFO. Но линия

frames[i].image = frames[i + 1].image;

просто копирует ссылку, а не данные текстуры. Думаю, это должен сделать DataTexture, но я не могу получить DataTexture из Texture или HTMLVideoElement.

Есть идеи?

Внимание! у вас должна быть камера и разрешить браузеру использовать ее, чтобы примеры работали. И, очевидно, у вас должен быть обновленный браузер.


person Alessandro Pezzato    schedule 25.09.2012    source источник
comment
Не уверен, что понял, но должен быть способ сделать это без копирования байтов вручную, просто вращая указатели. У меня был аналогичный проект, и я использовал несколько экранных холстов и встроенный drawImage() для переноса на экран. Это очень быстро, потому что Chrome выполняет всю работу непосредственно на графическом процессоре. Итак, если вы хотите использовать шейдеры/three.js, я бы подготовил окончательный холст и просто обновил текстуру. Имеет ли это смысл?   -  person Torsten Becker    schedule 26.09.2012
comment
Да, я сделал это в аналогичном проекте на C++. Вращение указателей — это САМЫЙ способ, см. это изображение. Но каждый новый кадр необходимо копировать в массив истории изображений (каждый раз в другом месте). Если вы копируете не данные, а только указатели, вы теряете старые кадры, потому что каждый указатель будет указывать на более новый кадр,   -  person Alessandro Pezzato    schedule 26.09.2012


Ответы (1)


Это то, что вы ищете??

http://fiddle.jshell.net/m4Bh7/10/

Редактировать:

function onFrame(dt) {
    if (video.readyState === video.HAVE_ENOUGH_DATA) { /* new frame available from webcam */
        context.drawImage(video, 0, 0,videoWidth,videoHeight);
        frames[framesNum - 1].image.data = new Uint8Array(context.getImageData(0,0,videoWidth, videoHeight).data.buffer);
        frames[framesNum - 1].needsUpdate = true;
    }
}

Это самая важная часть: она делает копию кадра и сохраняет ее как данные в dataTexture.

function rotateFrames() {
    for (var i = 0; i != framesNum - 1; ++i) {
/*
         * FIXME: this does not work!
         */
        frames[i].image.data = frames[i + 1].image.data;
        frames[i].needsUpdate = true;
    }
}

Затем данные копируются из текстуры в текстуру в кадрах.

новая версия: http://fiddle.jshell.net/hWL2E/4/

function onFrame(dt) {
    if (video.readyState === video.HAVE_ENOUGH_DATA) { /* new frame available from webcam */
        context.drawImage(video, 0, 0,videoWidth,videoHeight);
         var frame = new THREE.DataTexture(new Uint8Array(context.getImageData(0,0,videoWidth, videoHeight).data.buffer) ,videoWidth,videoHeight);
        frames[framesNum - 1] = frame;
        frames[framesNum - 1].needsUpdate = true;
        sprites[framesNum - 1].map = frames[framesNum - 1];
    }
}

Он генерирует новую текстуру для каждого кадра видеоизображения.

function rotateFrames() {
    for (var i = 0; i != framesNum - 1; ++i) {
/*
         * FIXME: this does not work!
         */
        frames[i] = frames[i + 1];
        sprites[i].map = frames[i];

    }
}

это то, что делает его лучше. Поскольку он повторно использует использованные текстуры, это означает, что его не нужно повторно отправлять на графический процессор.

person Gero3    schedule 26.09.2012
comment
Это то, что я искал. Пожалуйста, объясните в ответе, что вы делаете, и я приму ответ. Когда вы вызываете frames[i].image.data = frames[i + 1].image.data;, вы копируете фреймбуфер или просто перемещаете ссылки? - person Alessandro Pezzato; 26.09.2012
comment
Я добавил небольшое объяснение и лучшую версию. - person Gero3; 26.09.2012