В этом году я участвовал в категории PC 1k intro конкурса демосцены Assembly 2019 с моей работой Fluid Dynamics 101 и занял 3-е место (см. 1st, 2nd и 4th). Это побайтовый анализ записи. Правила конкурса заключаются в том, что вы должны создать исполняемый файл или веб-сайт размером всего 1024 байта. Это крайне ограниченное пространство для создания аудио и видео. Этот первый абзац уже имеет длину 515 байтов или символов, поэтому вся запись только в два раза длиннее.

Сжатие и загрузка PNG

Чтобы получить немного больше, чем просто 1024 символа HTML и JavaScript для работы, мы можем сжать JavaScript в изображение PNG, которое затем мы позволяем браузеру декодировать и выполнять. Вот окончательный файл HTML, который содержит данные изображения PNG в начале и HTML и JavaScript, необходимые для декодирования и выполнения в конце. Браузер будет игнорировать данные PNG при чтении их как HTML, поскольку он не знает, что с ними делать, и просто выполняет HTML, когда видит это. Когда тот же файл читается как PNG-изображение, в заголовке указывается, сколько байтов нужно прочитать, а HTML-часть находится за его пределами, поэтому она снова игнорируется, и файл отлично работает как PNG-изображение.

Я использую немного адаптированный пайплайн компиляции, который мы видели в Core Critical. Вместо того, чтобы полагаться на JSEXE, выполняющий PNG-фикацию, я решил сделать это сам, вдохновленный записью p01 о BLCK4777. Использование более оптимизированного кода начальной загрузки сэкономило мне 3 байта по сравнению с версией JSEXE. Еще 3 байта были сэкономлены за счет лучшего сжатия PNG с использованием комбинации PNGOUT, ZopfliPNG и PNGWolf. Таким образом, в целом этот подход сэкономил 6 байт. Приведенный выше код должен работать в любом современном браузере. Вы можете сэкономить 4 байта, удалив контрольную сумму IDAT, и Chrome все равно с радостью запустит ее, но Firefox этого не сделает.

Давайте сначала откроем часть HTML. ‹canvas id=s› позже используется в сжатом JavaScript для создания контекста WebGL, который позволяет нам запускать симуляцию жидкости и рендеринг на графическом процессоре. Моделирование жидкости тяжелое, и ЦП будет недостаточно быстрым, чтобы запустить его в разрешении 1080p со скоростью 60 кадров в секунду. Остальная часть HTML и JavaScript сначала загружает файл как изображение PNG во второй холст, затем считывает изображение как символы в переменную с именем «_» и, наконец, оценивает его как JavaScript.

Конвейер рендеринга и синтез речи

Теперь давайте посмотрим, что скрыто в этом сжатом разделе. Ниже вы можете увидеть его после декомпрессии. Поскольку он был минимизирован со всеми удаленными разрывами строк, пробелами и т. д., его по-прежнему очень трудно читать.

Чтобы сделать его более читабельным, я добавил в код отступы, разрывы строк и комментарии. Если бы вы удалили их, это было бы идентично приведенному выше коду.

Аудио и JavaScript — очень сложная комбинация для 1k интро, потому что нет простых способов получить доступ к Audio API в браузере. Альтернативы в основном пишут WAVE и воспроизводят его с помощью элемента Audio или с использованием API веб-аудио. Оба они занимают более 100 байт, чтобы произвести даже самый маленький звуковой сигнал. К сожалению, настройка нескольких текстур и этапы имитации жидкости занимают такой большой объем кода, что просто нет места для такого количества байтов для аудио. SpeechSynthesis API, с другой стороны, занимает всего 30 байт в сжатом виде, поэтому здесь он идеально подходит.

На самом деле запись была готова и упакована с использованием цикла setInterval() в JavaScript. Однако это время от времени вызывало микрозаикание, когда частота обновления экрана не совсем соответствовала скорости симуляции. Заметив заикание, я не мог его развидеть и просто должен был это исправить. Переход на подход requestAnimationFrame(), который является правильным способом сделать это, стоил мне дополнительных 10 байтов и занял еще 4 часа оптимизации, чтобы уместиться в 1024 байта. Конечным результатом является гладкая симуляция идеальной жидкости, которая делает меня очень счастливым.

Моделирование жидкости

Гидродинамическое моделирование является почти точной копией того, что представлено в Главе 38. Моделирование быстрой гидродинамики на графическом процессоре. Для экономии места некоторые этапы были объединены. Я также отбросил граничные условия, что создает несколько странные взаимодействия по краям, но это 1k, мы не ищем здесь идеального реализма.

Мы не можем позволить себе иметь несколько текстур для хранения скорости, давления и дивергенции, поэтому все состояние симуляции сохраняется в одной текстуре. Затем мы читаем текстуру A и записываем в текстуру B, а затем меняем их местами после каждого вызова отрисовки, за исключением случаев рендеринга, поскольку мы не хотим сохранять это, просто отображаем их. Красный и зеленый каналы используются для хранения скорости по осям X и Y, синий — для давления, а альфа — для дыма, который используется для рендеринга.

Будущая работа

Вот и все. Моделирование жидкости и синтезированный звук речи в 1024 байтах. Я думаю, что с этой технологией не так уж много места для творчества в 1k пространстве. Я не знаю, сколько места занимает настройка текстур и шейдеров в нативном коде, но, по крайней мере, к звуку получить доступ гораздо проще, так что, возможно, что-то можно сделать с этой стороны. В браузере вы можете опустить звук, чтобы улучшить визуальное оформление, однако немые интро не очень увлекательны, а с дополнительными 30 байтами не так уж много работы.

Тем не менее, в интро 4k, 8k или 64k, я думаю, вы могли бы с большим эффектом использовать как плавную симуляцию, так и синтез речи. Я не видел слишком много вступлений, использующих их, и, как показано здесь, ни одно из них не занимает много места. Кроме того, SpeechSynthesis API позволяет изменять звук с помощью тегов SSML, поэтому вы можете заставить его что-то петь, а не просто читать исходный код монотонным голосом.