Шестьдесят кадров для рекорда: игра Three.js, семь пролетов и стена ЭЛТ | Кодропс

Шестьдесят кадров для рекорда: игра Three.js, семь пролетов и стена ЭЛТ | Кодропс



Я создаю музыку под двумя именами. LXSTNGHT это темный, будущий гараж и даунтемпо. Ф/ПАМЯТЬ бежит хардвейв и чилл. И я создаю для Интернета. Музыка важна для этой истории потому, что она требует: соединять разные вещи, которые я создаю (дорожки, смоделированную геометрию, код реального времени), в отдельные части. Соединительная ткань — это лаборатория, галерея экспериментов, построенная на Three.js и React Three Fiber, где каждая деталь существует для того, чтобы дать музыке место для жизни.

В этом ограничении оказался весь метод. Демо может быть демонстрацией технологий; Релиз должен сохранять настроение в течение трех с половиной минут при частоте 60 кадров в секунду на любой машине, которой владеет слушатель. Цель всегда одна: кинематографические изображения, запускаемые в браузере. Настоящий свет, настоящая атмосфера и бюджет кадра, выдерживающий контакт с чужим оборудованием. Так что лаборатория стала местом, где рендерера спрашивают: сколько на самом деле стоит этот эффект, из чего на самом деле сделан этот кадр, почему тот кадр умер.

Эта статья представляет собой обзор трех направлений работы и уроков Three.js, которых они мне стоили: ГРАНИЦА3D Space Invaders с моими песнями в музыкальном автомате; тот Серия LXSTNGHTсемь пролетных миров, работающих на одном общем движке; и /фмстена неисправных ЭЛТ-мониторов, воспроизводящих запись F/MEMORY. Геометрия моделируется в Blender, это домашнее правило, здесь нет ничего примитивного с умным шейдером. Но эта статья о другой половине конвейера: что происходит после useGLTF решает.

ФРОНТИЕР: игра

Играй → lab.filipzrnzevic.com/frontier

FRONTIER — это Space Invaders, поставленная в виде трансляции: воксельный флот, запеченный в Blender, открытая палуба, растворяющаяся в тумане, одна прожекторная установка и симуляция, которая запускает весь бой вне React. Флот отправляется как один Draco GLB и отображается как стопка InstancedMesh пулы: шесть типов захватчиков в двухкадровом ступенчатом марше, по два слота материала на каждого, плюс боссы, которые разрушают воксель за вокселем, пока вы разбираете их корпус.

Пол представляет собой шейдер, потому что каждая текстура не удалась.

Колода прошла четыре полных отказа (доска с текстурой холста, плоский отражатель, дисплей с черным зеркалом), и каждая версия воспринималась неправильно по разным причинам: туман, поднимающий средние тона, блеск окружающей среды на отражателе, зеркальный лепесток ключевого источника света, базовый цвет, который никогда не был полностью черным. Побег заключался в том, чтобы вообще прекратить транспортировку поверхности, а затем восстановить землю по мере необходимости. один аналитик ShaderMaterial: шестиугольная решетка, рассчитанная на основе функции шестигранного расстояния с fwidth() сглаживание. Никакой текстуры, никакой мип-цепочки, четкости на каждом расстоянии и ничего, что могло бы передать неправильный цвет.

Когда пол стал шейдером, он мог стать инструментом. Решетка выполняет собственную математику тумана, поэтому она растворяется в тумане сцены, а не борется с ним. Он получает настоящие карты теней, которые настраиваемые ShaderMaterial можно сделать, если вы включите Three.js shadowmap куски и объявить изменения, которые ожидают эти куски. И в качестве входных данных он принимает бой: небольшой однородный массив излучателей обеспечивает тягу корабля, и каждая падающая бомба протягивает по плиткам настоящую лужу света. Энергия события смещает решетку в вершинном шейдере и пятистрочный JavaScript-двойник этого смещения (fieldLift) позволяет каждому захватчику, бункеру и падению перемещаться по той же поверхности, которую изгибает графический процессор.

Урок, который обобщает: земля, изготовленная по индивидуальному заказу шейдера, невидима для вашей осветительной установки. Свет сцены не касается ShaderMaterial если только вы не вскормите их сами. Патрульный прожектор неделю прочесывал этот борт и ничего не освещал, пока он не стал униформой.

Меню стали чем-то в переулке

Между волнами вы выбираете улучшение. Первая версия была модальной, три карты, игра ставилась на паузу за сеткой, и вся фигура выравнивалась. Поставленная версия: три шестигранные ворота стоишь в переулке и приближаешься к тебе, пока флот идет. Вы получаете улучшение, пролетая через него. Тот же ввод, что и в остальной части игры, без пауз, и выбор чего-то стоит, потому что взятие левых ворот означает отказ от правых.

Та часть, которая до сих пор заставляет меня улыбаться: RingGeometry(r, r + 0.34, 6) является шестигранное кольцо. Собственная камера правления, втиснутая в дверной проем. Никакого моделирования, никакого авторинга, шесть сегментов.

Рекорд — причина существования игры

Музыкальный автомат проигрывает F/MEMORY, полную пластинку, сначала самый новый трек. Правило, которое я бы дал любому, кто создает музыкальную игру: саундтрек — это продукт, звуковые эффекты — это знаки препинания. Каждый звуковой эффект в FRONTIER проходит через один глобальный автобус, который резко пригибается во время воспроизведения трека, поэтому двадцатиминутная пробежка — это двадцать минут прослушивания с боем наверху, а не наоборот.

Сколько стоит бой, измерено

Полученные данные со стенда без головы на реальном графическом процессоре (M1 Max, Chrome на ANGLE/Metal): в середине боя, при 5,2-мегапиксельном буфере рисования весь кадр 2 мс времени графического процессора на 95-м процентиле. Рой, проход теней, размытие HDR, композит, все это. Игра никогда не была заполнена. Три вывода, полученные в результате его получения, стоит украсть напрямую:

Бюджетные пиксели, а не соотношение пикселей устройства. dpr={2} на большом окне незаметно передал игре 9,7-мегапиксельный буфер рисования. Одна и та же конфигурация запуска на 5К-дисплее и 14-дюймовом ноутбуке различаются по пикселям более чем в 2 раза на такой же ДНР. FRONTIER ограничивает буфер абсолютным бюджетом пикселей (5,2 МП, с уровнями LOW/HIGH в настройках) и извлекает из него DPR. Идентичный выход, половина заполнения.

Никогда не ставьте mix-blend-mode поверх холста WebGL. Вспышка смерти представляла собой полноэкранную завесу DOM с mix-blend-mode: color. В каждом кадре было видно графический процессор браузера процесс потратил 30–45 мс на компоновку всего 5-мегапиксельного холста по медленному пути Скии. Невидимо для любого внутристраничного профилировщика: проходы отрисовки измерялись невинными, основной поток простаивал, а игра все еще зависала. Вуаль теперь представляет собой объединенный эффект композитора, тот же CSS color смешайте математику в пятнадцати строках GLSL. Если вы оцениваете холст, оцените его в холст.

Свет переключает интенсивность, а не видимость. Three.js записывает количество света сцены в шейдер каждого освещенного материала как константу времени компиляции, поэтому это значение является частью ключа кэша программы. FRONTIER сохранил точечные источники света внутри групп, которые переключались visible (корабль, босс, лучевое оружие), и первый кадр каждого драматического вступления менял количество света и перекомпилировал примерно 20 программ в середине боя: несколько сотен миллисекунд полной остановки, всегда «во время взрыва», в течение нескольких недель.

                                     {/* always visible */}
        {/* the hull toggles */}
    
  
            {/* always counted */}

Свет с интенсивностью 0 все еще занимает свое место в счетчике, поэтому программный ключ никогда не меняется. Это одно структурное изменение привело к тому, что в середине боя количество компиляций шейдеров уменьшилось с одной или двух за прогон до нуля, а общее количество программ — со 140 до 98. Полная охота, включая то, как три разных профилировщика лгали, прежде чем один сказал правду, — это отдельная детективная история, и о ней будет отдельная статья.

LXSTNGHT: один двигатель, семь миров

Полка → lab.filipzrnzevic.com/lxstnght

Серия LXSTNGHT состоит из семи пролетов (лонжерон, дымоход, объем, нарушение, гипостиль, костный мозг, заброшенный), созданный для продвижения пластинки. Каждый из них — это место: скученный заброшенный корпус, биомеханический коридор, шахта печи, по которой вы поднимаетесь, 84-метровый зал для процессий. Листаешь, летаешь, музыка играет.

Следует сразу сказать одно: это эксперименты, и они находятся на очень разных стадиях доработки и оптимизации. У некоторых уже есть билеты на полное выступление, некоторые до сих пор платят за свой первый пропуск. Полка для этого и нужна. Весь смысл в том, чтобы продолжать продвигать каждый из них дальше, делать его более кинематографичным и лучше оптимизированным для браузера, а приведенные ниже уроки показывают, чего будет стоить это продвижение.

Они остаются пригодными к отправке в качестве ряд из-за одного контракта: среда выполнения отправляет имя материала. HullMetal получает трехплоскостной состаренный металл и статическую дозировку. Strip и HoleGlowMat являются излучательными практиками. Reactor* — это световой локатор, скрытый во время выполнения, из которого создаются объемные сцены. Поменяйте GLB, оставьте движок: камеру, HUD, пост-стек, аудиокарту, все уже подключено. На скамейке даже есть запасной кусок(epigraph), созданный в основном для того, чтобы доказать, что обмен работает.

Это архитектура. Остальная часть этого раздела посвящена проектированию Three.js, с которым столкнулась серия: дорогостоящие уроки с указанием части, за которую заплатили за каждый из них.

Звонки с розыгрышем: 1421 → 25, затем половина из них отменяется (лонжерон)

longeron представляет собой 30-метровый коридор, перенесенный из сцены Blender и содержащий около 1500 объектов. Первое измерение: 1421 вызов отрисовки для 568 тысяч треугольников. Один звонок на болт. Привязка к вызову отрисовки, поэтому дисплей 5K сканировался, а количество треугольников выглядело нормально.

Исправление классическое: клонируйте каждую геометрию, запекайте ее. matrixWorld внутри, разбить на общий набор атрибутов, сгруппировать по названию материала, mergeGeometries. 25 вызовов отрисовки, без визуальных изменений.

Затем коррекция, которая является более полезной половиной. Одна 30-метровая сетка на материал означает, что его ограничивающая сфера всегда пересекает усеченную пирамиду, поэтому слияние молча отключило отсечение по пирамидальной пирамидеи весь коридор был представлен в каждом кадре. Я отклонил это, полагая, что коридор, если смотреть вниз по его собственной оси, не имеет ничего за пределами обзора. Правда о том, что впереди. Совершенно неправильно насчет того, что позади тебя. Повторное объединение по материалам за 3-метровый z-сегмент вернули отбраковку и обрезали представленные треугольники на 21–37% в зависимости от того, где вы стоите.

И трюк, который вообще делает объединенные сцены анимируемыми: слияние уничтожает идентичность каждого объекта, поэтому записывать идентичность в атрибуты вершин, пока она у вас еще есть. Во время слияния каждый исходный объект записывает свой центр ограничивающей рамки и его хэш в два настраиваемых атрибута. Это то, что позволяет одной объединенной стене нести световую анимацию для каждой панели, при этом каждая панель в любой момент освещается ровно, а не размазывается градиентом.

HDR — это дисциплина, а не флаг (лонжерон, костный мозг, заброшенный, нарушение)

Внешний вид сериала такой toneMapped: false Излучение достаточно горячее, чтобы Блум ореол, а реальные значения HDR перемещаются через композитор. Три жука научили меня тому, что на самом деле требуется, и все трое носят маскировку:

Буфер композитора является 8-битным, если вы не скажете иначе. Коридор продолжал «кроветь белым» на протяжении шести попыток исправления (металличность, высота освещения, порог цветения, экспозиция), и фактическая причина заключалась в по умолчанию используется 8-битный кадровый буфер: излучение с интенсивностью 14 обрезается до 1,0. до тональное отображение, а уровень усиления усиливал обрезанное плато. frameBufferType={THREE.HalfFloatType}. Это необходимо любому композитору, несущему HDR-излучения.

По умолчанию Блум использует оператор LDR. Самая продолжительная ошибка в серии — черные фигуры со светящимися ободками на трех частях — свелась к postprocessingБлум не выполняет свои обязательства BlendFunction.SCREEN: 1-(1-scene)(1-bloom). Когда сцена и оба значения Bloom превышают 1,0, что в точности соответствует горячему излучательному ореолу, два отрицательных числа умножаются на большие положительные, и результат становится отрицательным. (1-9)(1-3) = +16так 1-16 = -15. Черный. Это даже объясняет, почему повышение излучательной способности приводит к тому, что вещи худший: интенсивность от 4 до 9 превысила порог переворота. Один реквизит: blendFunction={BlendFunction.ADD}. Аддитив никогда не может инвертироваться.

Сорт может чеканить NaN. BrightnessContrast является линейным. При контрасте 0,12 черный отображается до -0,068. 8-битный буфер мог бы это зафиксировать; буфер HalfFloat, который вы только что успешно установили магазины это, а затем код sRGB Three.js оценивает pow(negative, 0.41666). NaN, который отображается белым цветом. Исправление — эффект зажима пяти линий, расположенный сразу после уклона. Если вы видите белое пятно, которое появляется только при включенной оценке, проверьте это, прежде чем прикасаться к чему-либо еще.

Свет, который путешествует (дымоход, лонжерон)

Визитной карточкой серии является движение света сквозь архитектуру. Заряд бежит по 28-метровой неоновой рельсе, гребень скользит по стене из панелей. Два правила сделали его таким:

Волна означает, что прибор ВЫКЛЮЧЕН. В каждой ранней версии трасса была освещена и ехала с модуляцией сверху, и ничто не считалось путешествием, потому что по всей длине всегда было что посмотреть. Версия, которая работает, удерживает полоску черный и пробегает по нему одной яркой головкой: пилообразная с коротким рабочим циклом, жесткая smoothstep передняя кромка, длинный хвост. Если остальная часть светильника все еще светится, вы создали модуляцию, а не волну.

Присадка, белая. Голова добавляет почти белый сдвиг поверх собственного цвета прибора, намеренно превышающий 1,0 в буфере HalfFloat, поэтому Bloom выделяет ореол именно на гребне. Умножение просто делает полоску более яркой версией самой себя. Добавление — это то, что продает его как плату.

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

Музыка…



Источник

Оставьте комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Прокрутить вверх