Facebook недавно представил новую функцию, 3D-фотографии, или, как они называют это в своем javascript: 2.5D-фотографии. Вот как это выглядит:
Чтобы создать такую фотографию, выберите «3D-фото» при публикации в Facebook и используйте новый портретный режим на iPhone. Вот и все.
Но как это работает под капотом? Мне нравится узнавать новые идеи, читая чужой код. Мне было достаточно любопытно узнать, как они реализовали этот эффект в Facebook. Вот история. Если вы просто хотите узнать о технологиях, перейдите к разделу «как все работает».
Первое предположение, фрагментный шейдер?
Существует популярный способ имитации 3D с помощью шейдера с использованием карты глубины и искажения пикселей изображения с помощью фрагментного шейдера в WebGL:
Сначала я подумал, что команда facebook пошла на это, потому что это очень легко сделать, а размер изображения довольно маленький. Но они сделали это не так. 🤔 Вы можете увидеть острые углы при изменении глубины в реализации facebook.
Еще одна идея, которую может использовать Facebook, - это смещение вершин на основе изображения, подобное тому, которое мы недавно использовали с Денисом на его сайте loveiko.com:
Есть еще несколько способов подделать это, но теперь мне нужно было знать, как они это сделали! Потому что мне любопытно, знаете ли.
Как я декомпилировал
Лучше всего начать с вкладки сети в DevTools. Все отсортировано по размеру файла, и вот что вы получите для этого кенгуру:
Скачал самый большой файл, оказался файл .glb. Это двоичная форма формата glTF, лучший выбор для 3D-моделей в Интернете.
Итак, я зашел в онлайн-программу просмотрщик glTF, загрузил этот файл и увидел следующее:
Не очень полезно, но теперь я знал, что речь идет не о смещении вершины-фрагмента, здесь речь идет о реальной 3D модели.
Итак, я пошел к исходным текстам javascript на странице Facebook (используя это расширение) и обнаружил, что они используют фреймворк Three.js для этого средства просмотра. Хорошо, я знал, как с этим справиться.
Нашел (на самом деле это самая сложная часть) объект сцены three.js и просто изменил одно значение:
material.wireframe = true;
Наконец-то я смог увидеть магию этого эффекта!
Как все это работает?
Прежде всего, когда новый iPhone делает снимок в портретном режиме, он также сохраняет данные о глубине вместе с обычным .jpg. Вот небольшое видео-объяснение того, как он его собирает:
Согласно спецификации Apple эти данные представляют собой облако точек. Не сетка.
Затем facebook на основе некоторого алгоритма интерполяции создает из нее настоящую 3D-модель с фотографией в качестве текстуры:
Теперь, когда вы загружаете страницу facebook, она запускает сцену three.js и загружает эту модель с текстурой.
Когда вы перемещаете мышь - положение камеры меняется, поэтому вы ощущаете приятный эффект 2.5D. Как мы только что выяснили, это на самом деле настоящее 3D.
В конце концов
Я не знаю, почему Facebook выбрал более сложный и технологичный способ создания этого эффекта. Может быть, потому, что у них уже есть программа для 3D-просмотра, или они планируют в ближайшее время что-то большее. Без понятия.
По-прежнему любопытствуя о точном алгоритме, используемом для создания модели glTF из поля глубины, в частности, обратите внимание, что эта часть не просто «глубина», а больше похожа на отдельный объект на фоне фона.
Думаю, это какая-то особая интерполяция глубинных данных. Но может быть у вас есть другие идеи? Может быть, это информация TrueDepth, которую мы можем извлечь из фотографии?
Также на каждую 3D-фотографию дополнительно загружается одно странное (возможно, просто тестовое) изображение:
Благодаря Майклу Фельдстайну, он раскрыл эту тайну, так что это изображение - PreMultipliedRadienceEnvironmentMap, которое threejs использует для упаковки вместо кубической карты mipmapped.
Вот и все. Надеюсь, вам понравилось это небольшое расследование. Буду признателен, если вы поделитесь своими идеями по этому поводу. Хорошего дня!
Спасибо Роману Вабищевичу за то, что разрешили мне использовать ваши фотографии!
P.S .: На самом деле я сделал много таких декомпиляций в прошлом году, 55 видео с реализованными различными интерфейсными эффектами (в основном на русском языке).