MarioKart64JS переходит в 3D: карты из Wii, 3D-титульный экран и облёты камеры после финиша
Mario Kart 64 рисует гонщиков плоскими спрайтами. Нажмите 3 в MarioKart64JS, и каждый карт станет 3D-моделью, включая Lakitu, с настоящими тенями, заново построенным 3D-титульным экраном и камерой, которая после финиша облетает ваш карт. Вот как собирался 3D-режим, в скриншотах.
Прошлый пост про MarioKart64JS был о том, чтобы как можно точнее повторить Mario Kart 64: геометрия трасс, спрайты и музыка из картриджа и новый JavaScript, делающий то же, что делает код оригинала на C. Этот пост — о движении в обратную сторону. Одна клавиша, 3, включает 3D-режим, которого у N64 никогда не было.
Спрайты становятся моделями
Гонщики в Mario Kart 64 — не модели. Каждый из них — это 321 заранее отрендеренный кадр 64×64, и игра выбирает кадр, соответствующий углу камеры. Именно это рисует и MarioKart64JS, и по умолчанию делает так до сих пор.
3D-режим заменяет эти спрайты моделями Standard Kart из Mario Kart Wii, взятыми из экспортов Collada, которые переносит в проект tools/build-wii-karts.py. Всё началось вечером 9 октября с одного теста: в 21:22 клавиша 3 поставила под игрока красный Standard Kart с Mario внутри. К 22:02 такой был у всех восьми гонщиков, с разделением по весовым классам Wii: маленький карт для Toad, средний для Mario, Luigi, Peach и Yoshi и большой для D.K., Wario и Bowser, у каждого своя раскраска.
Большая часть работы между этими моментами ушла на мелочи, которые загрузчик моделей делает неправильно:
- Глаза. Каждая текстура глаза — это один глаз. На Wii матрица текстуры удваивает его, а сэмплер зеркально отражает в пару. ColladaLoader из Three.js отбрасывает и то и другое, поэтому один глаз растягивался на всё лицо.
kart3d.jsвозвращает повтор и отражение для каждого персонажа. - Шины. Задние шины — это увеличенный меш передней шины. Их размер и положение осей измеряются по собранной модели каждого карта из меню, благодаря чему задние шины стали в 1,29× больше и встали туда, где они находятся на Wii.
- Сиденья. Каждый гонщик получает позицию сиденья, чтобы сидеть в откинутом кресле, а не парить над ним.
Agent! не может смотреть на картинки, поэтому проверял модели числами: ASCII-видами каждого карта сбоку, сзади и сверху, листами поворотного стола с 12 ракурсами и измеренными зазорами между руками каждого гонщика и рулём.
Гонки в 3D
В гонке клавиша 3 заменяет каждый карт на трассе, а не только ваш, а следующее нажатие возвращает спрайты. Вместе с этим меняются ещё две вещи.
Тени. У спрайтов под ними плоское пятно тени. 3D-карты отбрасывают на трассу настоящие тени из карты теней. Для этого понадобился трюк: трасса рисуется неосвещёнными материалами, которые не могут принимать тени, поэтому у трассы есть прозрачные копии её поверхностей — ловцы теней, видимые только там, куда падает тень.
Lakitu. Судья становится Lakitu из Mario Kart Wii (src/lakitu3d.js). Его руки позируются через собственные кости модели: одна держит удочку, другая машет флагом. Стартовые огни, таблички кругов и знак неправильного направления висят на крючке удочки, а кадр анимации исходного спрайта по-прежнему задаёт тайминг, так что отсчёт «красный, красный, синий» загорается тогда же, когда и всегда.
У 3D-карта есть ещё и корпус, которого не было у спрайта. При столкновении со стенами это капсула — по кругу над каждой осью, — и он движется и поворачивается как твёрдое тело. У этого были побочные эффекты. На Koopa Troopa Beach передний круг доставал до кромки трамплина раньше центра карта, и тыльная грань кромки сбрасывала карт с прыжка. Исправление проверяет каждую ось относительно земли под ней. Более поздний коммит запретил стенам поворачивать карт игрока при лобовом ударе, потому что в Mario Kart 64 стена отражает движение карта и никогда не меняет направление, куда он смотрит.
3D-титульный экран
Фон титульного экрана Mario Kart 64 — одна плоская картинка 320×240. Небо, холмы, дорога и пятеро гонщиков на ней нарисованы. Нажатие 3 на титульном экране перестраивает его (src/title3d.js): небо, холмы и дорога сделаны в Three.js, а гонщики — те же 3D-карты, что и в гонках.
Расположение повторяет картину. Wario впереди слева, за ним Bowser, Mario впереди справа, за ним Peach, а Toad выезжает из правого поворота. Каждый карт расставлен так, что его рамка на экране попадает примерно в 10 пикселей от рамки его гонщика в оригинальном рисунке. Камера стоит низко на дороге перед ними с широким объективом 64°, а дорога прокручивается под ней, поэтому кажется, что карты едут прямо на вас. Клетчатый флаг, логотип, PUSH START и копирайт — по-прежнему 2D-оверлеи из оригинального титульного экрана.
Меню за ним тоже получили подходящие фоны. Включение 3D на титульном экране заодно переключает на уровень текстур 4×, и гонки начинаются в 3D, пока вы снова не нажмёте 3.
Облёты после финиша
Когда вы пересекаете линию, Mario Kart 64 передаёт камеру короткой кинематографической сцене. MarioKart64JS следует для этого коду камеры игры (PLAYER_CINEMATIC_MODE и функции кинематографических планов в декомпиляции): камера разворачивается к передней части карта и смотрит, как он пересекает линию, а затем переключается между планами, пока ваш карт берёт под управление компьютерный гонщик. Последовательность повторяется: облёт носа, обочина, высокий кран, обочина, низкий план сзади, обочина. Одна оговорка из комментариев в исходниках: длительность и дистанции планов подобраны на глаз, а не взяты из таблиц ROM.
Следящие планы следуют за сильно сглаженной копией направления карта. Без этого мелкие подруливания ИИ раскачивали камеру вокруг карта, и казалось, будто он поворачивает рывками. С 3D-картами именно в этих планах модели видны лучше всего, ведь камера наконец видит карты спереди и сбоку.
Как делались скриншоты
Каждая картинка в этом посте снята в headless Chrome в разрешении 1280×960. Для кадров титульного экрана и выбора игры на титульном экране нажимается 3, так же как это сделал бы игрок. Гонки идут на автопилоте с сохранённым 3D-режимом, а облёты снимались так: игрок ставился на последний отрезок финального круга, и после финиша кадр сохранялся каждые 0,7 секунды. Agent! выбирал кадры с помощью измерений: положение камеры относительно карта подсказывало, к какому плану относится каждый кадр, а статистика пикселей отсеивала тёмные или малодетальные кадры. Как и в прошлом посте, сам он на них не смотрел.
Попробовать
Клонируйте AgentiLoop/MarioKart64JS, выполните npm install && npm run dev, откройте http://localhost:5173 и нажмите 3 на титульном экране или в гонке. Веб-сборка тоже включает 3D-карты, Lakitu и 3D-титульный экран. Перенесённые модели лежат в public/wii/; tools/build-wii-karts.py и tools/build-wii-lakitu.py — скрипты, которые перенесли их из файлов Collada.
MarioKart64JS — фанатский исследовательский проект для проверки того, насколько далеко ИИ может зайти в копировании игры. Mario Kart 64 и Mario Kart Wii — © Nintendo, и их ассеты принадлежат Nintendo. Проект не связан с Nintendo и не одобрен ею.