Спойлер: собаку пришлось перерисовать с нуля. Но обо всём по порядку. А больше всего времени занял скульптинг груди ;-)

В прошлый раз Claude за полтора часа перевёл досовскую демку Quake на нативный DirectX 12, пока я ходил на кухню. Демка Alone in the Dark лежала в соседней папке, в той же самой папке Heroes 2 и просто дх12 порта мне показлось мало…

апд: обновил футажик. теперь видно в сравнении работу длсс

Задумка

Сначала всё было скромно. Сделай как с Quake: рекомпил, нативный DX12, никаких врапперов, векторы движения для DLSS 5.

Потом я посмотрел на результат и понял, что хочу больше. Он понял. Вот это, наверное, и есть вайбкодинг в чистом виде: ТЗ без единой запятой там, где она нужна, и с «кк?» в конце.

Часть 1. Просто порт

Исходников самой игры 1992 года, понятно, нет. Зато есть FITD (Free in the Dark) от yaz0r, открытая реимплементация движка под GPL, которая работает с оригинальными файлами. Только рисует она через bgfx, окно делает через SDL, а звук играет через SoLoud.

Всё это Claude выкинул и написал на замену своё: рендер на DirectX 12, окно на Win32, звук на XAudio2. Музыка AdLib никуда не делась, эмулятор чипа YM3812 сидит внутри движка и кормит XAudio2 буферами. Окно 1600x1200, как я люблю.

Демка, кстати, сразу упала. Дважды. Первый раз потому, что в ней меньше спрайтов, чем ждёт движок от полной версии, второй раз потому, что движок после вступления пытался загрузить седьмой этаж особняка, которого в демке просто нет. Обе ямы он залатал.

С DLSS тут вышла забавная штука. Alone in the Dark считает 3D-модели на процессоре, каждую вершину, вручную. Поэтому прошлое положение каждой вершины известно точно, и векторы движения у Эмили и у монстров получаются настоящие, без угадывания. А вот фон в этой игре... это картинка. Нарисованная. Глубины у неё нет, векторов тоже, камера в каждой комнате стоит неподвижно.

Запомните это, к фону мы ещё вернёмся.

На порт ушло 40 минут: папку проекта он создал в 13:38, первую рабочую сборку закоммитил в 14:18.

Часть 2. Numpad 5

Полигоны. Модели в AITD собраны из отдельных кусков: лицо, грудь, рукава, всё отдельно, с дублированными вершинами на стыках. Он их склеил в одну сетку и дважды прогнал через сабдивижн Loop. Каждый треугольник превращается в 16. Острые сгибы (воротник, края книги) остаются острыми, всё остальное округляется.

Первая версия округлила вообще всё. Окна стали овальными, бумажки на полу тоже. Пришлось учить его отличать угол прямоугольника от изгиба.

Текстуры. Вот тут мне понравилось больше всего. Он взял палитру, которой рисовал художник в 1992-м, и по цвету каждого полигона определил материал: зелёное и синее у Эмили это ткань, коричневое на мебели это дерево, тёплое светлое это кожа, тёмное тёплое у людей это обувь и ремни. Дальше я сказал ему зайти через Chrome-аддон, и он сам зашёл на Poly Haven и скачал пять материалов под CC0: шерсть ёлочкой, дерево, металл, кожу и штукатурку. Каждый с картой нормалей и шероховатостью. Цвет художника остаётся основой, фотка даёт только фактуру.

Я в этом процессе нажал одну кнопку «Разрешить загрузку нескольких файлов».

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

Фоны. Real-ESRGAN, увеличение в 4 раза. Видеокарты у него в облаке нет, так что нейросеть крутилась на процессоре, по 3-5 минут на картинку 320x200. Подменяет фон он попиксельно: где на экране меню или текст, остаётся оригинал, а затемнения палитры между сценами продолжают работать.

Слева оригинальный фон 320x200, справа он же после Real-ESRGAN
Слева оригинальный фон 320x200, справа он же после Real-ESRGAN

Баги. Их было много, и они были смешные

Сеточка на лице. Я прислал скрин: у Эмили всё лицо в мелкую клетку. Оказалось, материал определялся в момент, когда палитра была затемнена до чёрного (игра так делает при смене сцены). Почти чёрный цвет он принял за ткань, и Эмили целиком, вместе с лицом, получила текстуру шерсти ёлочкой.

Чёрные квадраты на ногах. Появлялись во время анимации, на долю секунды, я даже заскринить не успевал. В паре вырожденных треугольников нормаль считалась как деление на ноль, получался NaN, а блум радостно размазывал этот NaN в аккуратные чёрные квадраты.

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

Сверху: оригинал и чистый Real-ESRGAN. Снизу: первая версия защиты и финальная
Сверху: оригинал и чистый Real-ESRGAN. Снизу: первая версия защиты и финальная

Грудь. Тут цитирую себя же: «грудь пожалуйста все таки сделай более округлой... но чтоб у нас не получился tomb raider». Сделал. Потом, когда чинил прямоугольные окна, случайно сделал её обратно угловатой. Я заметил. Он вернул, а заодно поправил лицо: художник покрасил каждый полигон лица своим оттенком, и с нормальным светом это читалось как грани. Теперь у кожи один тон, а объём рисует свет.

Эмили: оригинал слева, Numpad 5 справа
Эмили: оригинал слева, Numpad 5 справа

Собака

Монстр на чердаке собран из 17 шаров: живот, голова, суставы, позвонки на шее. В оригинале это плоские кружки, и выглядит нормально. А вот когда шары стали честно освещёнными сферами, его запузырило. Реально, гроздь пузырей с зубами.

Я написал: «просто перерисуй собаку с нуля... ты понял? подвигай полигоны... и пр. чтоб она не была таким пузырем».

Он сначала вытащил из модели скелет: 114 вершин, 24 группы анимации, кто к кому крепится. Потом построил новое тело из 39 капсул: худой сгорбленный торс, бицепсы, длинный череп, толстая шея, тонкий хвост и шипы вдоль спины. Капсулы сплавил в одну поверхность (это через поле расстояний и surface nets, я загуглил, ничего не понял) и получил около 19 тысяч треугольников. Каждая вершина привязана к костям оригинальной анимации, так что монстр двигается ровно так же, как в 1992-м. Зубы, когти, глаза и ступни остались родные.

Сверху оригинал из шаров, снизу новая модель, с четырёх сторон
Сверху оригинал из шаров, снизу новая модель, с четырёх сторон

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

Анимация смерти, сверху оригинал, снизу новая модель
Анимация смерти, сверху оригинал, снизу новая модель

Самое смешное, что вживую он монстра так и не увидел. Его тестовая Эмили каждый раз уходила к столу и находила масляную лампу, а игра вставала на диалоге «You Find An Oil Lamp». Два длинных прогона, три десятка скриншотов, и на всех лампа.

Монстра увидел уже я, у себя:

Numpad 5 включён, монстр лезет в окно
Numpad 5 включён, монстр лезет в окно
То же самое в оригинале
То же самое в оригинале

Как он это всё тестировал

Как и с Quake: Linux в облаке, Wine, vkd3d и программный Vulkan на процессоре. Никакой видеокарты. Игра там бегает примерно на 7 FPS, а он гоняет её скриптами: нажать Enter, подождать, пройти вперёд, снять скриншот, переключить Numpad 5, снять ещё один.

Мою RTX 5090 он в этот раз не трогал вообще. Всё проверялось в облаке, а на настоящем железе уже смотрел я.

Кстати, оверлей NVIDIA игру не захватывал. Это не баг рендера: оверлей цепляется только к играм из своего списка, и exe надо добавить в NVIDIA App руками. А для роликов я попросил надпись ON/OFF в углу, теперь она есть, прячется на F8.

DLSS 5 сверху

Подключал через RenoDX. Ноутбук с RTX 5090 Laptop и Core Ultra 9 275HX. Без DLSS игра держит 60 FPS при загрузке видеокарты около 45%. С DLSS 5 видеокарта уходит в 100%, а FPS падает до 18, на одном из скринов до 33.

Результат? Зависит от того, что подать на вход.

Оригинал (OFF). Дизеринг фона 320x200 нейросеть воспринимает как фактуру, и весь пол превращается в мозаику из плиточек. Смотреть на это больно.

DLSS 5, Numpad 5 выключен
DLSS 5, Numpad 5 выключен

Ремастер (ON). Получается фото кукольного домика. Местами красиво, местами... ну, вы видите сами. Деревянные столбы превратились в красные шторы, бочки стали жестяными банками, а лицо Эмили размыло в призрака.

DLSS 5, Numpad 5 включён. Обратите внимание на столбы
DLSS 5, Numpad 5 включён. Обратите внимание на столбы

На других скринах цвета гуляют: всё уходит в жёлто-синий, ковёр становится серой плитой, а монстр в окне превращается в кучу тряпья.

DLSS 5, жёлто-синие цвета, ON
DLSS 5, жёлто-синие цвета, ON
То же самое на оригинале
То же самое на оригинале

Самый спокойный кадр из всех, на 33 FPS. Галлюцинаций меньше, картинка ближе к оригиналу, только Эмили поседела, а монстр стал тёмным пятном.

Самый спокойный кадр, 33 FPS
Самый спокойный кадр, 33 FPS

Отдельно смешно с надписью ON в углу. DLSS 5 её тоже перерисовал, стилизовал и сделал полупрозрачной. Значит, через RenoDX нейросеть обрабатывает весь готовый кадр, вместе с интерфейсом поверх. И, судя по всему, на мои честные векторы движения и глубину она даже не смотрит.

Так зачем всё это?

Главный вывод для меня такой: DLSS 5 очень сильно зависит от того, что ему дают. Пиксельный оригинал он превращает в мозаику, гладкий ремастер в кукольный домик. Нарисованный фон без глубины для него просто фотография, которую можно перерисовать как угодно, отсюда и шторы вместо столбов.

По цифрам. Около 5 500 новых строк кода: рендер, ремастер-режим, шейдеры, окно и звук. Экзешник весит 3 МБ. С 13:38 до 17:43, четыре часа, считая собаку.

Обещаю, в следующий файлы сложу на гит

Комментарии (10)


  1. TigerClaw
    15.10.2026 15:46

    Пока это похоже на самый ужасный фильтр для эмуляторов. При этом игра даже в своём ванильном виде ещё вполне играбельна и проходима. Но здесь для нормального ремастера пришлось бы конечно прям чуть ли не с нуля рисовать фоны и делать 3дмодели. Изначально все таки слишком низкое разрешение.


    1. SergiiDia Автор
      15.10.2026 15:46

      честно, думал, что прокидывание длсса поверх дх12, ещё и с нормалями, ещё и с переработанной геометрией, хоть как-то спасет ситуацию... Если сравнивать с софтвер рендером... выигрыш только в стабильности...

      если после кваки я был ещё хоть как-то воодушевлен. то Алон ин зе дарк, меня уронила с небес на землю :(


    1. LiliJulie
      15.10.2026 15:46

      Для полноценного коммерческого ремастера ручной труд художников и моделлеров заменить пока нечем) Да и пиксель-арт тех лет вообще плохо переносит попытки разгладить его современными пост-эффектами


      1. SergiiDia Автор
        15.10.2026 15:46

        Речь не идёт, о том, что взять и сделать коммерческий ремастер.

        Но сам факт... что ты берешь машину (условный, не всмысле вы лично), максимально глупо ей рассказываешь... подвигай полигоны... сделай красиво... я ничего в этом не понимаю... и машина берет... и делает... это ж miracle


  1. 413x
    15.10.2026 15:46

    А подписка у вас Pro в Claude? Её достаточно для таких штук?


    1. SergiiDia Автор
      15.10.2026 15:46

      в данный момент, у меня подписка мах (х20). но она используется для работы.

      в соседней теме про quake, меня спрашивали, во что мне обошлась генерация...

      если очень огрубить.

      то реворк квейка мне обошелся в доллар.
      а реворк алон ин зе дарк... примерно в 2 доллара. Точно не могу сказать, т.к. я параллельно занимался работой, и посчитать сколько потратил лимитов... могу на глаз.

      обычного за $20 должно хватать для таких штук.

      Модель опус 5.5 в режиме хай.


  1. kostya_sosed
    15.10.2026 15:46

    История с лампой хорошо показывает проблему автопрогона: скриншоты есть, а нужная сцена так и не проверена. Для монстра я бы сделал отдельный короткий сценарий со стартом из сохранения прямо перед его появлением, если FITD позволяет так воспроизводить состояние.

    И перед снимком проверял бы не только, сколько времени прошло, но и что тест действительно дошёл до цели: нужная комната, нужный актёр, нет открытого диалога. Если это состояние можно вывести в лог, зависание на «You Find An Oil Lamp» станет явным провалом теста, а не ещё одним кадром для анализа. Скриншот тогда уже проверяет внешний вид монстра, а не сам факт того, что игра запустилась.


    1. SergiiDia Автор
      15.10.2026 15:46

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


  1. LiliJulie
    15.10.2026 15:46

    Я даже не удивлен что попытка натянуть современный темпоральный апскейлер на статичные рисованные задники без буфера глубины закономерно превратила картинку в сюрреалистичную мазню) Алгоритму просто неоткуда брать информацию о пространстве сцены, и он начинает дорисовывать шторы вместо деревянных балок

    А компиляцию шейдеров под DX12 модель сама написала на HLSL или брала готовые шаблоны из открытых примеров?


    1. SergiiDia Автор
      15.10.2026 15:46

      Если вы посмотрите на мой канал.

      то модели в целом все равно, какие там задники, и какой буфер глубины. Я вон на ведьмака натягивал. Если покрутить все ползунки на "макс", то он выглядит примерно также как алон ин зе дарк.


      а по поводу HLSL, вот вам ответ самой машины))))))

      Написала сама, но не на пустом месте. В оригинальном FITD рендер идёт через bgfx, и у него есть свои шейдеры на языке bgfx (.sc, это почти GLSL): фон, маска фона, плоские полигоны, «шум», градиенты и сферы. Модель взяла их как спецификацию: что делает каждый проход и как палитра из 16 банков по 16 оттенков превращается в цвет. По ней она переписала всё заново на HLSL. Готовых шаблонов из DirectX-Samples и подобного там нет.

      Сверху добавилось то, чего в оригинале не было вообще. Это вывод motion vectors и глубины для DLSS, свет и материалы режима Numpad 5, подмена фона на апскейл с откатом на оригинальные пиксели, блум, композит и надпись ON/OFF. В итоге вышел один файл shaders.hlsl примерно на 600 строк.

      Компиляция в рантайме. Текст шейдеров зашит в exe, при старте его компилирует D3DCompile из системной d3dcompiler_47.dll (vs_5_0 / ps_5_0), потом из него собираются PSO. Отдельного шага сборки шейдеров и fxc в make нет. Обвязка D3D12 (root signature, дескрипторы, swap chain) тоже написана с нуля по документации API, без хелперов вроде d3dx12.h.