Попробовать онлайн Описание
Bluestone Lane — произведение длиной три-четыре минуты, которое работает прямо в браузере и рендерится в реальном времени. Сумерки на старой улице, ожидающей сноса: на другой стороне все рольставни опущены, на стенах — нарисованные краской круги с иероглифом 拆 («снести»), а одно здание уже наполовину разрушено. Лишь одна рольставня ещё поднята наполовину — это маленькая мастерская по ремонту бытовой техники, где на табурете у верстака по-прежнему сидит робот, которого старый мастер собрал из корпуса радиоприёмника, объектива фотоаппарата и водопроводной трубы.
Кликните, чтобы начать, — камера зайдёт с улицы внутрь и обогнёт робота, оказавшись перед его лицом. Удерживайте левую кнопку мыши или пробел, чтобы раскрыть диафрагму его объектива, — с первого раза это никогда не удаётся, так что отпустите и зажмите снова. Не отпуская, двигайте мышью: голова робота поворачивается следом, и везде, куда падает его свет, возвращается прошлое.
Первый акт — мастерская. За пределами луча — настоящее: всё пыльное и выцветшее, на полках паутина, на полу осыпавшаяся штукатурка и битое стекло, а телевизор на картонной коробке, настенные часы, настольный вентилятор и ламповый радиоприёмник сломаны. Там, куда падает свет, всё как прежде: телевизор показывает передачи, у радиоприёмника светится шкала и звучит мелодия, а маятник часов качается.
Через некоторое время та же мелодия едва слышно доносится с другой стороны улицы. Робот поворачивает голову, прислушиваясь, а кадр отъезжает к дверному проёму; свет робота начинает дрожать, в мелодию прокрадываются помехи, изображение то и дело теряет синхронизацию, и на последнем разрыве картинки следует переход ко второму акту.
Второй акт — улица. На какой бы из пяти магазинчиков на другой стороне улицы ни упал луч, тот возвращается в один из вечеров середины 1990-х — внутри горит свет, на балконах сушится бельё, у дверей на низеньких табуретках сидят соседи, — и слышны звуки именно этого магазинчика. Найденные магазинчики так и остаются освещёнными, а ещё не найденные зазывают вас вывесками и звуками. Пока вы смотрите, заряд тает. Последний взгляд робота возвращается к магазину электроники, откуда доносится та самая мелодия, и вся улица на мгновение загорается огнями; затем заряд иссякает, луч прерывисто мигает и гаснет, мелодия обрывается на полуфразе, и улица становится такой, какая она сейчас. Финал показан изнутри мастерской: робот по-прежнему смотрит на тёмную улицу, напротив зажигается лампа, а последняя строка гласит: «Он помнит эту улицу в огнях».
После финального титра кликните, чтобы посмотреть ещё раз. По умолчанию интерфейс на английском, а на титульном экране есть ссылка для переключения на китайский; на телефоне нажмите и удерживайте экран, ведя по нему пальцем. Рекомендуются наушники, а также браузер с поддержкой WebGPU, например свежая версия Chrome или Edge; в браузерах без WebGPU произведение автоматически переключается на WebGL2. При первой загрузке придётся немного подождать, пока скачаются модели и заранее скомпилируются шейдеры.
Как использовался Tripo
Tripo сгенерировал больше двадцати предметов в мастерской: робота, два ламповых радиоприёмника (один вскрыт для ремонта, другой закрыт), два кинескопных телевизора, настольный вентилятор, настенные часы, будильник, кассетный магнитофон, настольную лампу, паяльник, лупу, ящик для инструментов, шкафчик для деталей, верстак, 28-дюймовый дорожный велосипед, термос, эмалированную кружку, а также запасные руку, ногу и торс — плюс четыре сломанные версии, сделанные специально. Стены и пол комнаты, стеллажи с коробками на них, кабели, стена с инструментами и мелочи на верстаке — это геометрия, построенная в коде; ряд магазинов на другой стороне улицы — это две сгенерированные фотографии («сейчас» и «тогда»), а не модели.
- От референса к модели: каждый предмет начинается с продуктового рендера на однотонном светло-сером фоне, который затем отправляется в Tripo. Перед моделированием на вскрытом радиоприёмнике сравнили три подхода — прямой image-to-3D, цепочку «изображение → multiview → 3D» и 3D по собранному вручную листу с четырьмя видами, — и большинство моделей прошли по пути «изображение → multiview → 3D»: с детальной геометрией и текстурами, PBR-картами и удалённым из текстур запечённым освещением, чтобы сцену освещали настольная лампа, сумерки снаружи и луч робота.
- Робот: Tripo выдал его единым мешем — голова, тело и табурет срослись в одно целое. Вместо того чтобы отрезать голову, автор сделал роботу «мягкую шею» в вершинном шейдере: вес, вычисляемый по положению вершины, равен 1 в голове из корпуса радиоприёмника, 0 — в теле и плечах, а вдоль шеи и кабелей вокруг неё плавно меняется, поэтому при повороте головы каждая вершина закручивается вокруг шеи на свою долю угла. Ничего не разрезано, а значит, ни одному шву негде разойтись, и кабели при повороте наматываются на шею. Табурет отделён скриптом Blender, поэтому во втором акте робот целиком поворачивается на нём лицом к улице. Хромированный шильдик «上海» (Шанхай) на его лице и табличка «人民电器» (Народная электротехника) на груди — это геометрия самой модели, а по тому же дизайну сгенерированы запасные рука, нога и торс, которые висят на настенных крючках и стоят у верстака.
- Сломанные версии: чтобы настоящее за пределами луча и прошлое внутри него совпадали, телевизор на картонной коробке, настенные часы, настольный вентилятор и ламповый радиоприёмник получили по второй, разбитой версии — референс переделали так, чтобы предмет выглядел повреждённым, а затем смоделировали с теми же настройками Tripo. Обе версии стоят на одном и том же месте: в пикселях, которых касается луч, видна целая, в остальных — сломанная.
- Исходные меши в вебе: каждая исходная модель из Tripo — это около 1,9 миллиона треугольников и 4K-текстуры (у робота — 8K). Вместо децимации в Blender, которая рвёт швы текстур и вблизи оставляет белые трещины, автор упростил модели с помощью meshopt, сохранив швы, до нескольких уровней детализации — у каждого своя измеренная погрешность. Во время работы каждый объект показывает только тот уровень, чья погрешность не превышает одного пикселя экрана, а текстура не грубее экрана: вдали — более простые уровни, а по мере приближения — всё более детальные. В опубликованной версии самый детальный уровень отличается от исходного меша лишь на доли миллиметра. Сначала загружаются более грубые уровни, а остальные подгружаются по мере надобности и снова выгружаются, когда видеопамять выходит за пределы бюджета.
- Просмотрщик моделей: добавьте ?review к адресу, чтобы открыть режим осмотра с яркой подсветкой; перетаскивайте, чтобы вращать камеру по орбите, прокручивайте колесо для масштабирования и нажимайте 1–8 для заданных ракурсов. Дважды кликните по любой модели — камера плавно подлетит к ней, а в левом нижнем углу появятся её название и число треугольников исходной модели из Tripo.
Как это работает в браузере
Игрового движка нет: всё построено прямо на WebGPU-рендерере three.js с использованием Vite, а в браузерах без WebGPU произведение автоматически переключается на WebGL2.
Прошлое вычисляется попиксельно. Глаз робота отбрасывает конус света, и при рендеринге каждый пиксель проверяется на попадание в него: внутри конуса — целые модели, включённые телевизоры и более тёплая цветокоррекция; снаружи — пыльное, выцветшее настоящее, и по той же маске сменяют друг друга сломанные и целые версии. Две фотографии на другой стороне улицы точно так же переключаются между настоящим и прошлым, а витрина магазина электроники — настоящий маленький 3D-магазин, где телевизоры тоже показывают передачи.
Быстрый запуск и плавная работа держатся на трёх вещах. Все шейдеры компилируются асинхронно и параллельно, а объект, чей шейдер ещё не готов, в этом кадре просто пропускается, вместо того чтобы задерживать кадр. Экран загрузки по разу отрисовывает каждый объект в каждом проходе (предварительный проход глубины, основной проход и каждая карта теней), поэтому, когда вы кликнете, чтобы начать, посреди истории уже ничего не компилируется. А разрешение рендеринга ограничено примерно 2,1 миллиона пикселей (около 1080p) и автоматически снижается, когда кадры затягиваются. Когда модель меняет уровень, оба уровня рисуются одновременно на взаимодополняющих наборах случайных пикселей и за 0,35 секунды плавно сменяют друг друга, а временное сглаживание выравнивает переход, так что вблизи ничего не «выскакивает». Добавьте ?q=low, чтобы включить режим низкого качества (без ambient occlusion и отражений в экранном пространстве, с картами теней вдвое меньшего размера).
Звук складывается из полевых записей под CC0 и синтеза на Web Audio: вечерний шум улицы за дверью, гудение лампы дневного света и электросети, тиканье маятника, испытательный сигнал телевизора, сервоприводы робота и звук открывающегося глаза, а мелодия по радио — оригинальная, построенная на пентатонике. Во втором акте у каждого магазина на другой стороне улицы свой звук.
Попутно автор исправил ошибку в WebGPU-рендерере three.js r186: когда две модели различаются только способом хранения нормалей (Int8 против Int16), рендерер позволяет им использовать один пайплайн, поэтому та, что рисуется второй, читает свои вершины в неверном формате, и её поверхность освещается пятнистой мешаниной, похожей на камуфляж. WebGL2 это не затрагивает.


