Помните как Apple представила iOS7 c эффектом параллакса? Теперь это можно делать прямо в браузере.
На всех ноутбуках и телефонах сейчас есть камера, поэтому можно с помощью tensoflow моделей анализировать положения головы и глаз. Так же новая статья на SIGGRAPH 2020 расказывает как делать датасеты с фотограмметрией, удобные для эффекта параллакса.
Наверно всем известно что есть библиотека Tensorflow для нейронных сетей, она работает под языком Python и Javascript. Процесс свертки в нейронных сетях это достаточно тяжеловесное вычисление, которое хорошо параллелится и существуют версии не только для CPU, но и на CUDA под Python и WebGL/WebGPU под Javascript. Забавно, но если у вас не NVidia, то оффициальная сборка Tensorflow на языке Javascript будет на ПК будет работать быстрее, так как нет официальной сборки с поддержкой OpenGL. Но к счастью для всех TF 2.0 имеет модульную архитектуру, которая позволяет думать только о самой сути, а не языке, на котором это выполняется. Так же существуют конвертеры 1.0 -> 2.0.
На данный момент есть две официальные модели для распознования лица: facemesh и blazeface. Первая больше подходит для мимики и масок, вторая шустрее и просто определяет квадрат и характерные точки, такие как глаза, уши, рот. Поэтому я взял легковесный вариант — blazeface. Зачем лишняя информация? Вообще может быть можно существующую модель еще уменьшить, так как кроме положения глаз, мне больше ничего не нужно.
В браузере на данный момент существует 5 бэкендов: cpu, wasm, webgl, wasm-simd, webgpu. Первый СPU слишком медленный и его сейчас не стоит брать ни в каких случаях, последний два слишком инновационны и находятся на стадии пропосалов и работают под флагами, так что поддержка у конечных клиентов нулевая. Поэтому я выбирал из двух: WebGL и WASM.
По существующим бенчмаркам можно увидеть, что что для маленьких моделей WASM работает порой быстрее чем WebGL. Кроме этого, параллакс может использоваться с 3д сценами и запуская WASM бэкенд на них, я понял что WASM работает гораздо лучше, так как дискретные видеокарты ноутбуков, не вывозят одновременно нейросети и 3д сцены. Для этого я взял простую сцену с 75-ю гловами в .glb. Ссылка кликабельная и там WASM.
Если вы перешли по ссылке, вы наверно заметили, что браузер спросил разрешение на доступ к видеокамере. Возникает вопрос: что будет, если пользователь нажал нет? Разумно было бы ничего не грузить в таком случае и фоллбэчить на управление мышью\гироскопом. Я не нашел ESM версию tfjs-core и tfjs-converter, так что вместо динамического импорта, я остановился на довольно криповой конструкции с бибилиотекой fetchInject, где порядок загрузки модулей имеет значение.
Для того что бы найти положение взгляда, я беру среднее между двумя глазами. И легко понять что расстояние до головы, будет пропорционально расстоянию между глазами на видео, в силу подобия сторон треугольника. Данные о положении глаз, которые приходят из модели довольно зашумленные, поэтому прежде чем производить расчеты, я их сгладил с помощью скользящей средней EMA (Exponential Moving Average):
Или записав по другому:
Таким образом мы получаем координаты x, y, z, в некой сферической системе координат с центром в камере. Причем x и y ограничены углом обзора камеры, а z это примерное растояние от головы до нее. На малых углах поворота , так что x и y можно считать за углы.
Довольно забавный дата сет с публикации SIGGRAPH 2020 Immersive light field video with a layered mesh representation. Они делали картинки специально для того что бы можно было двигать камеру в некотором диапазоне, что идеально ложится под идею параллакса. Пример с параллаксом.
3д сцена тут создается послойно, и на каждый слой наложена текстура. Не менее забавно выглядит дейвайс, с помощью которого они создавали фотограмметрию. Они купили 47 дешевых экшн камер Yi 4K за 10к рублей каждая, и разместили их на полусферу в форме икосаэдра в котором треугольная сетка утроена. После этого все разместили на штатив и камеры синхронизировали для съемки.
На всех ноутбуках и телефонах сейчас есть камера, поэтому можно с помощью tensoflow моделей анализировать положения головы и глаз. Так же новая статья на SIGGRAPH 2020 расказывает как делать датасеты с фотограмметрией, удобные для эффекта параллакса.
Наверно всем известно что есть библиотека Tensorflow для нейронных сетей, она работает под языком Python и Javascript. Процесс свертки в нейронных сетях это достаточно тяжеловесное вычисление, которое хорошо параллелится и существуют версии не только для CPU, но и на CUDA под Python и WebGL/WebGPU под Javascript. Забавно, но если у вас не NVidia, то оффициальная сборка Tensorflow на языке Javascript будет на ПК будет работать быстрее, так как нет официальной сборки с поддержкой OpenGL. Но к счастью для всех TF 2.0 имеет модульную архитектуру, которая позволяет думать только о самой сути, а не языке, на котором это выполняется. Так же существуют конвертеры 1.0 -> 2.0.
На данный момент есть две официальные модели для распознования лица: facemesh и blazeface. Первая больше подходит для мимики и масок, вторая шустрее и просто определяет квадрат и характерные точки, такие как глаза, уши, рот. Поэтому я взял легковесный вариант — blazeface. Зачем лишняя информация? Вообще может быть можно существующую модель еще уменьшить, так как кроме положения глаз, мне больше ничего не нужно.
В браузере на данный момент существует 5 бэкендов: cpu, wasm, webgl, wasm-simd, webgpu. Первый СPU слишком медленный и его сейчас не стоит брать ни в каких случаях, последний два слишком инновационны и находятся на стадии пропосалов и работают под флагами, так что поддержка у конечных клиентов нулевая. Поэтому я выбирал из двух: WebGL и WASM.
По существующим бенчмаркам можно увидеть, что что для маленьких моделей WASM работает порой быстрее чем WebGL. Кроме этого, параллакс может использоваться с 3д сценами и запуская WASM бэкенд на них, я понял что WASM работает гораздо лучше, так как дискретные видеокарты ноутбуков, не вывозят одновременно нейросети и 3д сцены. Для этого я взял простую сцену с 75-ю гловами в .glb. Ссылка кликабельная и там WASM.
Если вы перешли по ссылке, вы наверно заметили, что браузер спросил разрешение на доступ к видеокамере. Возникает вопрос: что будет, если пользователь нажал нет? Разумно было бы ничего не грузить в таком случае и фоллбэчить на управление мышью\гироскопом. Я не нашел ESM версию tfjs-core и tfjs-converter, так что вместо динамического импорта, я остановился на довольно криповой конструкции с бибилиотекой fetchInject, где порядок загрузки модулей имеет значение.
криповая конструкция
Забавно то, что порядок расположения имеет значение и нельзя их оборачивать в один массив (Promise.All), так как это приведет к довольно не приятной ошибке, которая исчезает после первой загрузки и дальше не воспроизводится, так как скрипты попадают в кэш.
fetchInject([
'https://cdn.jsdelivr.net/npm/@tensorflow-models/blazeface@0.0.5/dist/blazeface.min.js'
], fetchInject([
'https://cdn.jsdelivr.net/npm/@tensorflow/tfjs-converter@2.0.1/dist/tf-converter.min.js',
'https://cdn.jsdelivr.net/npm/@tensorflow/tfjs-backend-wasm@2.0.1/dist/tfjs-backend-wasm.wasm'
], fetchInject([
'https://cdn.jsdelivr.net/npm/@tensorflow/tfjs-core@2.0.1/dist/tf-core.min.js'
]))).then(() => {
tf.wasm.setWasmPath('https://cdn.jsdelivr.net/npm/@tensorflow/tfjs-backend-wasm@2.0.1/dist/tf-backend-wasm.min.js');
//some other code
}
Для того что бы найти положение взгляда, я беру среднее между двумя глазами. И легко понять что расстояние до головы, будет пропорционально расстоянию между глазами на видео, в силу подобия сторон треугольника. Данные о положении глаз, которые приходят из модели довольно зашумленные, поэтому прежде чем производить расчеты, я их сгладил с помощью скользящей средней EMA (Exponential Moving Average):
pos = (1 - smooth) * pos + smooth * nextPos;
Или записав по другому:
pos *= 1 - smooth;
pos += nextPos * smooth;
Таким образом мы получаем координаты x, y, z, в некой сферической системе координат с центром в камере. Причем x и y ограничены углом обзора камеры, а z это примерное растояние от головы до нее. На малых углах поворота , так что x и y можно считать за углы.
pushUpdate({
x: (eyes[0] + eyes[2]) / video.width - 1,
y: 1 - (eyes[1] + eyes[3]) / video.width,
z: defautDist / dist
});
Фотограмметрия
Довольно забавный дата сет с публикации SIGGRAPH 2020 Immersive light field video with a layered mesh representation. Они делали картинки специально для того что бы можно было двигать камеру в некотором диапазоне, что идеально ложится под идею параллакса. Пример с параллаксом.
3д сцена тут создается послойно, и на каждый слой наложена текстура. Не менее забавно выглядит дейвайс, с помощью которого они создавали фотограмметрию. Они купили 47 дешевых экшн камер Yi 4K за 10к рублей каждая, и разместили их на полусферу в форме икосаэдра в котором треугольная сетка утроена. После этого все разместили на штатив и камеры синхронизировали для съемки.
john_samilin
так, теперь нам ждать кино с параллаксом?
munrocket Автор
не знаю, но точно с такой штукой начнут делать ассеты к играм)