Воксельный движок, дни с седьмого по двенадцатый
Дни со второго по шестой закончились 21 октября в 11:31 на версии 0.24.0: следующим планом стояло освещение, самый большой риск дорожной карты. Этот пост доходит до 27 октября, 18:52, и версии 0.32.0. За это время закрылись десять планов. Теперь движок освещает пещеру светящейся в ней породой и даёт этому свету отражаться. Он снова держит полную детализацию до 100 м в виде по умолчанию. И в нём есть замок.
По календарю отрезок короткий. Работа шла днём 21-го, весь день 22-го и 27-го. С 22:30 22-го до 07:03 27-го в репозитории не было ни одного коммита: у меня кончился недельный лимит. Все замеры кадра и CPU ниже снова сняты на моём ноутбуке, машине разработки из файла бюджетов: RTX 3080 Laptop GPU и Ryzen 9. Числа для Windows — с раннера CI. Движок делается вместе с первой игрой, и этот пост снова не о ней.
Порядок работы тот же, что в первый день. Каждый план идёт по фазам в линии, у агента со своей копией репозитория; фаза с пометкой human стоит, пока я не посмотрю на результат в окне; каждое закрытие проверяет свежий агент; а замеры GPU ждут тихой машины, когда ни одна другая линия её не нагружает. Два слова из прошлых постов: зеркало — это копия мира на GPU, а синхронизация — шаг, который приводит её в актуальное состояние.
Сначала одно изменение плана. 21-го, в коммите, где были набросаны следующие пять планов, я отказался от базовой карты: GPU класса GTX 1660, под который написан бюджет кадра, теперь, как сказано в дорожной карте, «не приобретён», и «нижняя планка остаётся гейтом на бумаге и читается как оценка по двум замерам, снятым на машине разработки». Взамен в файле бюджетов появилась вторая колонка, медленный адаптер: встроенная графика AMD того же ноутбука на драйвере RADV. Начиная с плана 0028 каждый план рендера снимает замеры на обоих GPU.
Свет
План 0024 одобрили на шестой день, но не начали. Начался он 21-го в 14:03 и закрылся 22-го в 08:35 версией 0.27.0, после двух ревью при закрытии.
Проход лучей больше не считает освещение. До 0.24 один compute-проход вёл луч, находил попадание и тут же освещал его налобным фонарём. Теперь кадр — это цепочка проходов, у каждого свой буфер вывода и своя строка в бюджете.
flowchart TB hit["проход попаданий: на пиксель позиция, нормаль, материал, полупрозрачный слой"] --> light["проход света: налобный фонарь плюс одна грань светящегося вокселя, выбранная из 8 кандидатов; один теневой луч"] samples["синхронизация зеркала извлекает светящиеся воксели в образцы света, по 16 байт"] --> light light --> temporal["временной проход: перепроецировать по позиции попадания, забыть историю внутри боксов правок кадра"] probes["объём зондов: 32 x 32 x 32 зонда, 1/8 обновляется за кадр"] --> gather["сбор непрямого света на пиксель"] temporal --> atrous["дисперсия, затем четыре шага фильтра a-trous"] gather --> comp atrous --> comp["композитинг и тонмаппинг"]
Один проход попаданий занимает 1,235 мс, а старый единый занимал 1,73–1,75. Ядру без шейдинга на AMD хватает 64 регистров, и оно ничего не сбрасывает в память; старому нужно было 84, и оно сбрасывало.
Проход света — это next-event estimation, стандартный приём трассировщика путей: луч целят в источник света, а не надеются в него попасть. Налобный фонарь сэмплируется напрямую, а у светящейся руды на каждый пиксель выбирается одна грань ресемплированием по значимости: случайно берутся восемь светящихся граней, и одна из них остаётся с вероятностью, которая зависит от того, насколько она осветила бы этот пиксель. С повторным использованием резервуаров в выборе участвует и грань, выбранная в прошлом кадре. Потом к выбранной грани идёт один теневой луч. Светящиеся воксели становятся образцами света при синхронизации зеркала, по шестнадцать байт, в буфере на 2²⁰. Первый же полёт его заполнил: 997 740 из 1 048 576. На одном только уровне 417 388 светящихся граней, и их извлечение заняло 25,9 мс. Фаза 6 остановилась на трёх порогах: шлейфы, дальняя зона кадра и 3,0 мс. Поправка в 15:39 вставила ещё и фазу для четвёртой проблемы: из-за дальних кандидатов проход света стоил от 5,3 до 12,2 мс против планки в 6,0. Из этой фазы вышел ADR-0025: каждый кадр строится таблица чанков с излучателями не дальше четырёх чанков от глаза; вес — мощность, делённая на расстояние. Цену он формулирует двумя фразами: «Оценка смещена по построению. Излучатель за радиусом не даёт ничего». С таблицей пик полёта упал до 18 522 образцов, ни одного вытеснения, ни одного отказа.
Арифметику проверяет закрытый ящик со светящимся потолком, где освещённость пола можно посчитать вручную: 1,7408. Движок показывает 1,7388, на 0,11 процента меньше. С таблицей ближних излучателей вместо равномерного выбора он показывает 1,7914, на 2,9 процента больше, зато ошибка на пиксель падает с 1,14 до 0,40.
Потом фаза 12, моя, вечером 21-го. В логе осталось, что я сказал:
сейчас картинка, которая мне нравится больше всего, но есть небольшая проблема: свет на тени всё время движется, хотя я ничего не делаю. Интересный эффект, если бы я видел свет от огня, который движется сам по себе, или пепел. но для постоянного света, который излучают жилы, это выглядит странно. хотя сам по себе эффект красивый
И короче: «f5 ничего не делает», «грубый теневой обход темнее, но заметной разницы в качестве нет» и «я должен видеть, какой сейчас режим, или хотя бы что он сменился». Ревью при закрытии отказалось закрывать план и добавило три фазы. У мерцания была простая причина, словами ревью: «смешивание никогда не опускается ниже ALPHA = 0.2, так что неподвижный пиксель вечно усредняет около девяти кадров оценки по одному образцу». Исправление дало свету от светящейся породы собственную историю, по умолчанию 32 кадра, а долю фонаря оставило на смешивании 0,2. Среднее изменение неподвижного пикселя за кадр упало с 0,57–1,04 до 0,15–0,18 по четырём конфигурациям. Итог ADR-0018: «Две истории, а не одна. Владелец видел, как статичный свет излучающих вокселей мерцает при неподвижной камере и общем коэффициенте смешивания 0,2». Теперь, когда режим меняют клавишей, он печатается на экране.
Утром 22-го я облетел его снова и доложил: «освещение в половинном, грубый теневой обход, повторное использование сэмплера, история правок, фонарь выключен, фильтр включён, пульсация руды выключена, история свечения 32 — всё нормально. нажатие f5 ничего не меняет». F5, которая переключает на градиентную историю, мне так ничего и не показала, и то, что эта история не сработала, приняли как есть. Эти настройки стали настройками по умолчанию: освещение в половинном разрешении, грубый теневой обход по блокам 2 × 2 × 2, повторное использование резервуаров. Грубый обход стал режимом по умолчанию только на той последней фазе, после того как я сказал, что не вижу заметной разницы в качестве.
Ракурс README на версии 0.32.0
Ограниченный уровень, сид 1, из вокселя (148, 280, 484), рыскание 135, тангаж −10, экспозиция 0,08, с настройками освещения по умолчанию и видом contour-sharp, 64 кадра, 1280 × 720 на RTX 3080.
Отрисовано одноразовым примером на основе заглавного кадра самого движка, потом удалённым; все флаги — из README.
Одна планка по-прежнему не выполнена: у извлечения образцов света при синхронизации p99 — 2,21 мс против 1,0, а худший кадр — 6,1. Я облетел ради неё мир с подгрузкой и написал «3 — всё хорошо», так что она записана как невыполнение, а рядом стоит моя оценка.
Промежуточный пояс
Шестой день закончился невыполненной планкой подгрузки и измеренной причиной: 41,8 процента синхронизации приходилось на копирование в буфер GPU. Это исправление уже однажды отвергли, как вариант Б в ADR-0017, так что план 0027 начался с ADR-0022, который это отклонение отменяет. Он берёт StagingBelt из самого wgpu: постоянно отображённые в память куски по 4 МиБ, и каждая загрузка — это запись в срез пояса и копирование из буфера в буфер в энкодере кадра. Про собственное кольцо, которое планировал шестой день, в плане сказано: «пояс — это и есть то кольцо, только куски возвращает сам wgpu». Строка итога ADR: «„Один memcpy в отображённую память“ — не бесплатно».
Фаза 2 остановилась 21-го в 14:25, потому что на сам пояс приходилось 28,9 процента синхронизации при пороге в пять. Я решил записать это как невыполнение и снять замер заново на тихой машине. На тихой машине медиана синхронизации в простом виде упала с 3,3–3,7 мс до 1,4–1,7, а Queue::write_buffer пропал из профиля, но всё обновление вместе с опросом по-прежнему занимало от 1,7 до 2,0 против планки в 1,0. В 19:11 я облетел его в 1440p: «полёт 1 прошёл нормально, но fps было около 30». Оверлей читал таймеры обратно на CPU и тем самым сериализовал CPU и GPU, так что тридцать кадров в секунду были не на совести пояса. План закрылся в 19:42 версией 0.26.0, с двумя записанными невыполнениями.
Половина кирпича для зеркала
Упакованный кирпич шестого дня вчетверо сократил данные на CPU, а зеркало на GPU не тронул. В ADR-0012 было три шага; последним стал план 0028, 22-го. Слот полного кирпича в зеркале теперь хранит те же упакованные байты, что и на CPU, в единицах по 64 байта: две единицы для кирпича из одного материала, три для двух, до восемнадцати для кирпича, где материалов больше шестнадцати. Слоты бывают десяти классов размера на страницах по 256 КиБ, и свободны только 0,10 процента единиц. Атрибут контура, который на шестой день стоил 1 168 байт на кирпич, теперь хранится только для поверхностных вокселей, с адресацией подсчётом битов: в среднем 197 байт на кирпич.
Фаза 3 остановилась в 10:35. Проход атрибутов на GPU показал p99 5,77 мс против 1,0, а кирпич на 99-м перцентиле ждал в очереди 7,6 секунды. В 10:59 я внёс поправку: убрать записи очистки, класть по четыре кирпича в рабочую группу и добавить порог в 250 мс на то, сколько кирпич ждёт. Итоговый проход показывает от 0,71 до 0,75 мс на p99, а кирпич ждёт 25 мс.
Важна здесь строка пещеры с подгрузкой. На шестой день действовало правило давления: когда зеркало заполнено больше чем на 90 процентов своих 3 ГБ, чанки полной детализации снимаются. Из-за него вид по умолчанию держал 12–13 чанков полной детализации, от 77 до 83 м, против «около 100 м» из дорожной карты, и файл бюджетов записал это как наблюдение. На 0.29.0 вид по умолчанию держит 16 чанков, 102 м, при 0,87 ГБ живых данных, 65 процентах бюджета. А синхронизация простого вида упала с 4,9 мс по медиане до 0,17, впервые ниже планки в 1,0. Синхронизация вида по умолчанию по-прежнему 3,1 мс, потому что маски поверхности считаются на потоке рендера, и теперь открытая часть планки подгрузки — именно она. Два моих полёта: «прогон 1 ощущается нормально» и «2 нормально».
Планка правки, третий заход
План 0031 шёл 21-го. Его первая фаза — профиль 100 выкапываний по стадиям: отсечение 34 процента, отрезки 27, запись слов 15. План стал строить слова формы прямо из строк-отрезков и считать строку каждого отрезка один раз на операцию, а не на каждый кирпич. Одна из его фаз сократила время на шесть–восемь процентов вместо ожидаемых 24. Два прогона на тихой машине прервали, потому что машина не была тихой, «kworker на 63 %, chromium на 78 %, скрипт omarchy на 100 %», и фаза около полутора часов ждала окна. Потом бенчмарк показал 1,00, 0,99 и 0,99 мс.
Бенчмарк воспроизведения упал со 103 мс до 61,3. В первый день планка выкапываний была тем бюджетом, в который движок не уложился в два с половиной раза; теперь она выполнена с двукратным запасом.
Отражённый свет
Непрямой свет пришёл с планом 0029 и ADR-0023 в виде объёма из 32 × 32 × 32 зондов освещённости с шагом 1,6 м, который сдвигается вместе с камерой. Каждый кадр один зонд из восьми, плюс каждый зонд, которого коснулась правка, пускает 64 луча полным обходом, 262 144 луча за кадр, и сохраняет то, что видит во всех направлениях, развёрнутым в карту света 6 × 6 и карту расстояний 14 × 14. Потом каждый пиксель собирает свет с зондов вокруг себя, а карты расстояний не дают зонду за стеной его освещать. Среди отвергнутых вариантов — все привычные названия: ReSTIR GI, voxel cone tracing, кэш освещённости на воксель, radiance cascades.
Этот план я смотрел чаще любого другого за эти дни, четыре сессии, и после каждой он менялся. Сессия 7, 22-го: «отражённый свет делает лучше, но бьёт по производительности»; «то же самое, выглядит лучше, но производительность плохая — у меня 10 fps», и это были пики синхронизации подгрузки; и «так гораздо лучше. но когда я выключаю свет, ещё какое-то время немного вижу его на стенах». С зондами через восемь вокселей: «ощущается неправильно — очень долго устаканивается». Сессия 8:
всё ещё есть задержка, и ощущается это очень неестественно, в реальности, если выключить яркий свет, я в первые секунды ничего бы не видел, а потом глаза постепенно привыкли бы к темноте, и я снова видел бы нормально
Эта фраза стала отдельным планом, 0040, адаптацией глаза, о ней ниже. А в этом плане из неё следовало одно: убрать задержку. ADR признаёт, что первая оценка была неверной: «Задержку нашёл владелец, и „полсекунды“ выше — неверная цифра для выключателя». Теперь изменение света открывает окно в 16 кадров, в котором обновляется один зонд из четырёх, а история не сохраняется вовсе. Сессия 9: «свет всё ещё долго гаснет», а пульсация руды «совсем плохая, вокруг сильное мерцание». Ещё через две фазы, в сессии 11 около десяти вечера: «почти мгновенно», «мгновенно», пульсация «нормально, без мерцания». План закрылся в 22:10 версией 0.31.0. В тестовой сцене после выключения фонаря его отражённый свет теперь падает ниже десяти процентов к 14-му кадру, а раньше — только к 58-му.
Коридор подземелья замка без отражённого света и с ним
Кадр замка dungeon, налобный фонарь включён, настройки освещения по умолчанию, 64 кадра в 1280 × 720 на RTX 3080; во втором кадре добавлен объём зондов.
Всё, что видно на втором кадре вне конуса и вдали от двух факелов, — отражённый свет.
Цена в точке появления в мире с подгрузкой: обновление и сбор вместе — от 1,63 до 1,66 мс против порога в 1,7, а всё освещение вместе с ними — 4,42–4,48 мс против планки в 6,0. На стороне AMD одно только обновление — 7,8 мс. Непрямой свет включается флагом, --indirect, а в моей доработке сказано, как я хочу его использовать: «оставить непрямой свет только для некоторых источников, вроде огня на палке или огня в подземелье, а для простых источников он должен быть выключен».
Апскейл, дважды
Апскейлер плана 0030 и ADR-0024 — собственный: лучи смещаются по 16-фазной последовательности Халтона, кадр рисуется во внутреннем масштабе 1×, 1,5× или 2×, а отдельный проход перепроецирует историю по позиции попадания и повышает резкость. В масштабе 1,5 кадр занимает от 2,73 до 2,78 мс, а в масштабе 1 — от 5,29 до 5,55, и апскейл вместе с повышением резкости и композитингом — 0,76 мс против планки в 1,5.
Моя первая проверка в окне, сессия 7: «всё очень размыто, особенно с налобным фонарём», «выглядит чуть лучше, всё ещё размыто», «выглядит очень размыто даже без контуров». Вердикт: переделать до закрытия. Переделка сузила ядро, стала брать историю фильтром Catmull-Rom, смешивать по близости и обрезать историю при смене света. Посреди неё, в 14:19, я попросил линию остановиться с контрольной точкой, потому что ноутбук работал от батареи. Сессия 8: «на прогоне 4 есть шлейфы, но уже не так сильно. может, это нормально как часть визуального стиля», «5 так себе», «6 почти нормально» (6 — кадр в родном разрешении), «7 так себе, слишком много движения теней». Так что по умолчанию остался родной кадр, апскейлер вышел включаемым по флагу, версией 0.28.0, а порт FSR 2 стал планом 0041.
План 0041 перенёс FSR 2.2.1 на WGSL, девять проходов. Он не влит: на отсечке его блок закрытия написан, а ревью ещё впереди. Фаза 7 была моей, 27-го, с 17:25 до 17:36:
fsr 2 вроде чуть мягче, но от нашего не сильно отличается
и «на fsr, наверное, слишком много деталей», и «я за наш 1,5 — с fsr всё равно разница небольшая». Ещё: «с нашим апскейлером мерцание, когда выключаю фонарь, похоже, минимальное». На ветке режимом по умолчанию становится наш апскейлер в масштабе 1,5, со смещением лучей.
Здесь FSR 2 стоит на 1,3 мс больше нашего, а большой разницы я не увидел.
Замок
Мне хотелось показать движок коллегам с работы. План 0042 набросали 22-го в 18:13, одобрили в 18:15, а закрылся он в 21:30 версией 0.30.0, без единой остановки фазы. Он написал для движка запись файлов .vox и генератор замка только на целочисленной арифметике: стены, четыре башни, надвратная башня, донжон-капелла с нефом, окном-розой и шпилем, винтовая лестница и подземелье с темницами и склепом. Это 27 тайлов, из которых оставлен 21; при генерации они штампуются в вырезанный зал 80 × 80 × 48 м через тот же путь префабов, что и своды шестого дня. Вектор детерминизма и эталон ворот проверяют его, как и всё остальное.
Мой просмотр в сессии 10 — ворота, неф, окно и подземелье: «замок выглядит потрясающе».
Замок на версии 0.32.0
Кадры замка из стенда, отрисованы headless в 1280 × 720 на RTX 3080 с настройками освещения по умолчанию и видом contour-sharp.
При экспозиции по умолчанию неф под одним налобным фонарём почти чёрный; что там есть, показывают объём зондов и повышенная экспозиция.
Замок не маленький. Его префабы занимают 343,6 МБ, из них около 92 процентов — воздух, файл .vox весит 52,6 МБ, пик процесса выше примерно на 0,3 ГБ, а чанк генерируется за 424–428 мкс против 186–189 для одного зала. Первый кадр появляется через 1,1–2,6 секунды, ниже планки запуска в три. Кадр ворот рисуется за 7,2–8,0 мс на RTX и за 51 мс на стороне AMD. Последний коммит этого отрезка, 27-го в 18:52, дал замку постоянное место: assets/architecture/, для переиспользуемых зданий; файлы .vox git игнорирует, и они пересоздаются командой из README.
Контуры на расстоянии вытянутой руки
В сессии 7 22-го, разглядывая апскейлер, я сказал про родной кадр, что он «выглядит несколько лучше, без контуров выглядит совершенно нормально». Контуры были режимом по умолчанию с пятого дня, а вблизи выглядели мягкими. План 0039 набросали в тот же день, чтобы это измерить. Он построил сцену для замера резкости — вырезанную стену на расстоянии вытянутой руки, с полосой мелких деталей, полосой средних, размытием края и двумя страховочными проверками — и пять кандидатов: взвешенную подгонку плоскости по 27 соседям, смещение с сохранением объёма, смесь с нормалями граней, более мелкую октаву шума породы и коэффициент детализации фонаря, применённый после освещения.
Первая фаза показала, что плоскость — не главная проблема. Разрыв в полосе мелких деталей между режимом граней и контурами на 74,6 процента объяснялся освещением в половинном разрешении. ADR-0011 получил строку итога: «Мягкость шла от пути освещения, а не от подгонки». Размытие края — на сколько пикселей размазан острый край стены — показало то же: 0,80 пикселя в режиме граней, то есть в простом виде, против 13,6 с контурами. Кандидат со смесью нормалей граней не прошёл страховочную проверку на полостях, 12,1° и 21,9°, и его отбросили.
План стоял с 22-го по 27-е вместе со всем остальным. Утром 27-го я сравнил пресеты и выбрал: «contour-sharp становится режимом по умолчанию», то есть взвешенная подгонка плюс коэффициент детализации после освещения, потому что «contour-grain поначалу выглядел естественнее всех, но кладёт на породу слишком много тёмных крапинок, хуже всего там, где фонарь скользит по стене (жёсткие чёрные пятна)». Перепроверяя с отражённым светом, я нашёл ещё одно: «contour sharp, похоже, наш выбор, но на второй сцене я видел артефакты от острых углов вокселей на некоторых гладких стенах», и это ушло в доработки. Проход исправлений нашёл, что коэффициент детализации масштабировал и отражённый свет, так что теперь композитинг держит прямой и непрямой свет раздельно. Цена — в пределах процента в обе стороны на обоих GPU, а байты зеркала не изменились. Версия 0.32.0, 27-го в 17:27.
Стена теста резкости в четырёх видах
Эталоны apps/flythrough/tests/sharpness.rs: вырезанная стена на расстоянии вытянутой руки под налобным фонарём, 320 × 180 на программном драйвере lavapipe, увеличены вдвое.
Фонарь так близко, что засвечивает стену; тест меряет полосы и края, а не приятную экспозицию.
Тесты и Windows
Вечером 22-го я попросил ревью кода всего репозитория и сказал про тесты: «ощущение, что их стало гораздо больше, чем было, и гоняются они бесконечно долго, надо оптимизировать прогоны». План 0043 разбил их на три уровня: quick — 470 тестов за 45,4 с без блокировки GPU; gpu — ещё 124, 201,5 с; full — ещё 5, 327,1 с. Задача CI на Linux сократилась с 981 с до 827.
Тем временем задача на Windows падала на каждом прогоне с тех пор, как план 0028 переписал шейдер атрибутов, и всегда на одном тесте: headless-полёт стенда, который должен завершиться за 120 секунд. Подозрение пало на FXC, старый компилятор шейдеров DirectX, который компилировал новый шейдер атрибутов. План 0046 встроил статический компилятор DXC, а ADR-0035 запрещает FXC навсегда, но с оговоркой: «То, что причина в FXC, — вывод из логов CI; локально FXC не запускали».
В тридцать раз быстрее, а тест в виде по умолчанию всё равно падал: 121,055 с при лимите 120: время уходило не на компиляцию прохода атрибутов, а на его исполнение в WARP. Исправление CI в 20:58 уже перевело этот тест на Windows на --look plain, и с ним задача зелёная; этот обходной путь остаётся. Версия 0.31.1 в 22:30 22-го стала последним коммитом перед перерывом.
27-е
Работа возобновилась в 07:03, рядом с планом 0039 были открыты три линии, и к вечеру каждой из них понадобился я.
Адаптация глаза, план 0040. План родился из фразы сессии 8 о том, что, когда гаснет сильный свет, сначала ничего не видишь. ADR-0033 предложен; проход экспозиции стоит 0,07 мс. К 10:28 были готовы четыре фазы, а моя сессия в 17:37 нашла следующую проблему: «самый медленный — лучший, но мерцание придаёт ему странный вид. когда я выключаю фонарь и сцена становится светлее, кажется, будто на стенах одна за другой загораются несколько ламп в течение 10–15 секунд, и это выглядит супер странно и неестественно». Поправка задаёт новые константы времени адаптации, но в код ещё не вошла.
Витринная каверна, план 0038. Поводом стала моя фраза 22-го: «заглавная картинка убогая, надо сделать что-то поинтереснее и без налобного фонаря, в большой пещере». План строит большую каверну с четырьмя рудами и фиксированными заглавными кадрами, 99 326 образцов света, кадры от 10,7 до 13,5 мс на RTX и от 76 до 100 на стороне AMD. Пять фаз готовы; шестая — мой просмотр.
FSR 2, план 0041, о нём выше, ждёт ревью при закрытии.
Последнее изменение харнесса в тот день, в 18:11: dev-линии и ревью при закрытии идут на Opus, рутинные задачи, которые не трогают код, — на Sonnet, и у каждой линии есть бюджет контекста.
Бюджеты на отсечке
На шестой день планкам освещения, шумоподавления и апскейла не с чем было сравниваться. Теперь замер есть у каждой строки таблицы кадра, кроме запаса, а все невыполнения — на пути данных с CPU в зеркало: синхронизация вида по умолчанию и извлечение света, а через них и планка подгрузки. Планки памяти выполнены все: 0,87 ГБ из бюджета мира в 3 ГБ при 16 чанках, ОЗУ сильно ниже 4 ГБ, а буферы вывода кадра вместе с зондами — 254 МБ против 1,5 ГБ. Код звука и коллизий за эти дни не менялся, так что эти разделы не сдвинулись, и два невыполнения микшера с шестого дня остаются.
Что дальше и что открыто
Следующая веха, M10, — под открытым небом; её набросали и одобрили утром 22-го: план 0032, солнце и небо, со своей тестовой сценой и лесом при низком солнце, о котором я попросил; 0033, дальний план до километра; 0034, жидкости; 0035, воздушная перспектива и облака; 0036, погода, с правилом ADR-0031 «в пещере всегда сухо»; 0037, ночное небо. ADR-0027 о тени от солнца формулирует приоритет одной фразой: «Лучше короткое тёмное мерцание, чем солнечный свет, протёкший в пещеру». Ни один из шести не начат. После них — два плана о здоровье кода по итогам ревью 22-го: шесть подтверждённых дефектов, среди них тест, который утверждает, что HUD не выделяет память, хотя он её выделяет, и разбор структуры разросшихся файлов: main.rs стенда на 5 771 строку и шейдер прохода лучей на 1 383.
Кроме того, открыто: три линии 27-го; синхронизация вида по умолчанию; извлечение света; острые углы на гладких стенах; материалы замка, у которых нет акустических значений для звука, так что под --audio камень замка не отражает; и DualSense на диване, до которого я так и не добрался.
Как это было организовано
Харнесс тот же, и с 22-го он записан: .claude/skills/orchestrate/ описывает одну оркестрирующую сессию, которая ведёт несколько линий планов одновременно, и каждая линия — dev-агент со своим git worktree. Линии по очереди занимают GPU через одну эксклюзивную блокировку, каждая команда идёт под лимитом памяти в 6 ГБ, линия останавливается на каждой фазе с пометкой human и ждёт меня у скрипта запуска, который открывает сборку в окне с нужными флагами, а каждое закрытие проверяет свежий агент-архитектор.