Графические трюки на Sega Mega Drive на примере игры Adventures of Batman and Robin

После предыдущей статьи о графической архитектуре Sega Mega Drive было бы интересно рассмотреть некоторые приёмы и трюки которые можно реализовать на этом железе. Игра Adventures of Batman and Robin примечательна обилием таких трюков, поэтому возьмём её для препарирования.

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



Сразу же после начала игры (момент 01:22) можно увидеть интересный эффект имитации перспективы. Причём в отличие от трюков с плоскостью заднего фона Mode 7 в SNES здесь мы имеем дело с выпуклой в разных местах сценой, что требует какого то иного подхода. В данном (и почти всех остальных) случае игра пользуется возможностью указывать разные значения горизонтального скроллинга для каждой строки/сканлайна изображения экрана.
Если посмотреть на содержимое заднего фона B в эмуляторе Exodus, то сразу после старта игры можно увидеть следующую картину:



Зеленый прямоугольник соответствует окну отображаемому на экране в данный момент. Сам же задний фон B содержит тайлы с «запеченной» картинкой зданий изображенных уже в перспективе. Сперва не очень понятны неровные стыки на краях, но если сдвинуться с места, то многое проясняется:



Так вот что тут происходит — при скроллинге экрана каждый его сканлайн скроллится независимо с разной скоростью — при выбранных скоростях и задней картинке это создаёт иллюзию глубины изображаемой зацикленной сцены. Действительно каждый сканлайн при этом проделывает в заднем фоне разный путь, чему соответствуют неровные границы сцены в фоне — какие то участки краевого изображения просто оказываются не нужны. Учтите еще что на картинке виден не весь задний фон B, но правая его часть полностью симметрична видимой левой.
Так же обратим внимание на «парящую дымку» в верхней части экрана. Она содержится в слое A и выглядит в отладочных окнах эмулятора вот так:



Здесь можно увидеть два момента — во первых «синусоидальное» движение дымки обусловлено тоже построчно меняющимся скроллингом во вторых — в Sega Mega Drive отсутствует эффект полупрозрачности слоёв, поэтому когда нужно сделать имитацию полупрозрачности игры формируют слой из полностью прозрачных и непрозрачных пикселей в шахматном порядке. Эффект грубоватый, но другого на Sega Mega Drive не было.

Если теперь перемотать на 41:35 — то здесь будет аналогичный по горизонтальному скроллингу эффект, но с добавлением еще и вертикального независимого скроллинга столбцов, что даёт еще более богатую перспективу.
Теперь вернёмся на 15:45 — здесь мы увидим одновременное управление и горизонтальными и вертикальными смещениями как массивами для создания иллюзии частичного вращения слоёв, причём один слой по HBlank разорван на 2 якобы независимых.

Момент 16:30 — одновременное управление и горизонтальной и вертикальной перспективами — апогей техник независимого скроллинга сканлайнов выше. За счёт «срезки» слоёв на границах как бы крыш зданий создаётся полная иллюзия 3D.
Давайте поглядим что при этом происходит в видеопамяти. Картинка экрана:



Смещения сканлайнов фонового слоя A в видеопамяти при этом выглядят так:



Момент 30:20 — здесь луч прожектора сделан весьма непростым образом. Слой B отображает облака вполне прямолинейно, а вот слой A изображает полупрозрачный луч прожектора. Вариация размеров круглого пятна и «хвост» тоже создаются изощрённой подменой сканлайнов на лету на некоем трафарете. Причём сам трафарет представляет из себя ровный большой прямоугольник перечеркнутый по ровной диагонали границей разделения между пустотой и шахматной сеткой луча.
Выделю два момента для анализа. Первый:



… с такими вот смещениями сканлайнов:



… и когда луч прожектора убегает вперёд:



… паттерн сканлайнов приобретает следующий вид:



На деле статичная картинка распределения сканлайнов тут не отражает всей сути происходящего — как в комментариях заметил Shiru игра подменяет у текущего сканлайна по hblank не только горизонтальную позицию в фоне для выбора места где начинается луч прожектора, но и перескакивает с линии на линию фона по вертикали чтобы выбрать необходимую ширину луча в нужном месте. И в самом деле в эмуляторе картинка видеопамяти постоянно «подрагивает», так что статика не отражает всего — линии в динамике на самом деле идут непоследовательно.

35:10 — еще один босс имитирующий небольшие повороты через управление слоем.

47:10 — классическая в общем то имитация гоночной трассы.

53:10 — эффект «трубы», еще одна, встречающаяся не в одной игре, техника имитации перспективы — оба слоя трудятся по разные стороны от спрайтов и тоже каждый сканлайн скроллится с разной скоростью.

Такое обилие разных изощрённых эффектов в одной игре на мой взгляд уже граничит с демо–сценой. Как видно картинку на Sega Mega Drive даже без Mode 7 можно было значительно обогатить.

15 комментариев

avatar
Эффект с прожектором в общем-то прост. Рисуем в слое графики фона как бы треугольник — сначала один пиксель, потом два, потом три, и так далее до полной ширины. Теперь с помощью прерывания по HBlank в каждой строке мы можем вывести в эту строку линию нужной ширины — просто выбираем нужное вертикальное смещение в слое фона для задания ширины линии и нужное горизонтальное смещение для её позиционирования по горизонтали. А имея возможность вывода линий любой ширины мы можем нарисовать на экране любую выпуклую фигуру, это самый обычный рендер полигона (буфер xmin-xmax, рисуем круги и линии алгоритмом Брезенхема).

В Clockwork Tortoise скорее всего были выходцы с демосцены, как в Zyrinx. Либо Jesper Kyd на них так повлиял.
  • Shiru
  • +4
avatar
Техника да, понятна, я её там же и описал по своему, непонятно как сформировалась полученная в эмуляторе картина сканлайнов — она не совсем соответствует картинке если переносить линии одну-за-одной как в первых рассмотренных эффектах. Наверное каждая линия может соответствовать сразу нескольким линиям в итоговом изображении из-за подмен по hblank, то есть рендер построчно перескакивает с линию на линию не только горизонтально, но и вертикально.
avatar
Я и говорю: изменением вертикального смещения слоя фона для текущей строки выбирается ширина отрезка на экране.
avatar
Да, без изменения смещения по вертикали тут не получится.
avatar
Вот прямо чувствую, что нет полного понимания эффекта, и моё объяснение не очень понятно. Конечно не получится без смещения по вертикали, суть эффекта в этом и стоит.

Попробую объяснить ещё раз. Эффект состоит из двух частей.

Первая часть 'рисует' залитый круг и трапецию в буфер в основном ОЗУ. Это самая обычная техника рисования полигона. В буфере для каждой строки всего два значения — самая левая точка и самая правая точка отрезка (xmin,xmax). Рисуем круг алгоритмом Брезенхема (потому что быстро): получаем координату точки, смотрим строку в буфере. Если точка нужна левее, чем левая — значим меняем в буфере на более левое значение. Если нужна правее, чем правая — тоже. Таким образом получается буфер ширины и смещения горизонтальных линий на экране, из которых состоит залитая фигура. Эта техника позволяет рисовать только выпуклые фигуры, то есть букву H ей не нарисовать (нужно два отрезка в пределах одной строки). Более сложное объяснение, если вдруг формулами понятнее, чем на пальцах: www.enlight.ru/faq3d/articles/24.htm

Вторая часть просто решает задачу быстрого вывода требуемых линий на экран, имея в распоряжении только железо SMD. С помощью изменения смещений слоя фона по HBlank мы можем вывести любую строку слоя фона в любую строку экрана. Заранее рисуем в слое фона все возможные ширины отрезков, какие нам понадобятся (т.е. от 1 до N пикселей). Теперь смотрим по буферу, подготовленному первой частью эффекта — надо отрезок шириной в три пикселя? Выводим третью строку слоя фона, где как раз и есть отрезок шириной в три пикселя. При этом смещаем её по горизонтали в нужное место экрана. Если у нас отрезок шириной в три пикселя не в одной строке экрана, а во многих — значит во все эти строки выводим строку фона с тремя пикселями.
avatar
Не не, эффект я понял сразу же. Я почему то забуксовал с наложением его на картину видеопамяти из эмулятора — смутно брезжило, что линии перескакивают и по вертикали, но уверенности не было. Теперь немного исправил пост, чтобы читателям тоже было понятнее.
avatar
После таких статей о приставках совсем иначе смотришь на эти игры.
avatar
Практически «прикладное демостроение». С той лишь разницей, что сперва эти эффекты появились в играх и только потом перекочевали в демосцену. Независимый скролл каждого сканлайна на олдскул платформе был реализован в Coma Light 13, например, в 2012 году :).
avatar
Не факт что и откуда первое пришло. Например выше тут упоминается команда Zyrinx — они пришли из демосцены и сделали игру Red Zone для Sega Mega Drive и настолько гордились тем что сделали, что прямо в титульных экранах игры вставили вот такую заметку:



Стоит сперва начало посмотреть до первых геймплейных моментов (не пропуская заставки), а потом перемотать на 7:40 и позырить на indoor-геймплей.
avatar
Вот indoor-эффект я до сих пор не смог раскусить до конца (аналогично ещё в Toy Story, но попроще). Т.е. я знаю, как это делается в общем случае, не на SMD, но если большинство эффектов из игр на SMD/SNES я повторить на них же готов и точно знаю, как это сделать, то этот — нет. Я бы стал делать честный рендер углов стен с подгрузкой графики в видеопамять, но они обходятся (довольно большим) набором статичных тайлов.
avatar
Провёл небольшое исследование в том же эмуляторе Exodus.
А прикольно у них там.

На слое А рисуется потолок и «внешние углы». Они реально перерисовываются при движении под нужный угол.
На слое Б рисуется пол и «внутренние углы». Даже если там статичные тайлы они значит рассчитаны под любой ракурс который может дать игра. Возможно их истинное число просто невелико, учитывая что есть флаги отражения тайлов по осям.
Так или иначе углы действительно создаются на лету тайлами или их содержимым и разбиты разумно на оба фона как «внутренние» и «внешние».
avatar
P.S.
Что-то сюда картинка как то косячно загрузилась. Вот она же на фастпике: i91.fastpic.ru/big/2018/0925/be/6ce8e44d70e132d8ab446c2e3df679be.gif
avatar
P.S.
И судя по всему кусок стены над дверью еще накрыт спрайтами, а не фонами. Три больших таких спрайта прямо над ней. В общем не без заморочек.
avatar
P.P.S.
Посмотрел сейчас еще в тайлы угловых стен — да, они не перерисовываются динамически, а построены заранее.
Есть два одинаковых набора — в одном два разных цвета (внутренние стены), в другом один из цветов прозрачный (внешние стены). В каждом изображены линии под разными углами — судя по всему растиражированы почти все возможные углы от 0 до 45 градусов, а дальнейшее получается зеркалированием по горизонтали/вертикали. С другой стороны, если приглядываться к итоговой картинке, то нередко заметно, что линия не является идеальных Брезенхемом, нередко видны «шероховатости» видимо на стыках, то есть прямо все возможные пиксельные комбинации возможно даже не покрыты для краткости. Общий паттерн же таков, что берется пиксель вдоль одной стороны и из него проводится линия ко всем пикселям на противоположных сторонах. Есть еще подозрение, что с помощью палитр еще сокращается число нужных комбинаций. Но так да — с ходу трудно придумать как этим теперь рисовать, такую задачу мне тоже еще не доводилось решать.
avatar
Я предполагаю, что теоретически для фиксированной проекции каждой конкретной точке экрана должен однозначно соответствовать конкретный статичный вектор. Т.е. если мы смотрим на точки ближе к центру, там линия стены идёт под острым углом к зрителю, а у точек ближе к углам экрана линия идёт в направлении угла. Значит по экранным координатам угловой точки всех восьми вариантов углов стен нижнего слоя можно однозначно определить, какую линию надо нарисовать.

Можно заготовить карты тайлов с заранее нарисованными фиксированным набором графики всеми возможными углами, размером типа 4x4 тайла для четверти всех возможных случаев (т.к. три четверти экрана можно отзеркалить), и каждый кадр дорисовывать в карту тайлов каждый угол. Т.е. нужен массив размером в четверть экрана с индексами нужных тайлов (8 бит), это будет порядка 128*112=14 килобайт, плюс набор карт тайлов углов (256 карт 4x4 займёт 4К, 256 углов определённо должно хватить) — по меркам платформы это совсем немного для такого киллер-эффекта.

В общем, идеи есть, и наверное мой вариант сработает и будет достаточно быстрым, но я не уверен, что в Red Zone сделано именно так. Это такой эффект, где надо поэкспериментировать и предусмотреть много разных мелочей. Его реализация не читается однозначно по визуальному анализу, в отличие от большинства приставочных эффектов.
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.