Точка зрения
Alone Coder
Не совсем очевидно,но проекция простра─
нства на экран из одной точки ничего не
говорит о расстояниях, сколько бы мы ни
крутились-вертелись в разные стороны. Поэ─
тому такие проекции строить гораздо легче,
чем настоящее 3D,и этим можно пользоваться
и в играх ( Myst III: Exileи т.п.).
* * *
Рассмотрим простейший случай - пусть мы
(камера) стоим в одной точке и крутим го─
ловой только в стороны. У нас всего одна
степень свободы. Что мы видим?
Мы видим то же самое, как если бы мы
стояли в середине цилиндра с натянутой на
нём текстурой. Или то же самое,как если бы
мы стояли в середине куба. Или призмы. Это
не имеет значения.
Цилиндр проще всего в реализации,потому
что он позволяет при любом угле поворота
пересчитывать экранные координаты в коор─
динаты в текстуре простым лукапом по таб─
лице (это будет большая таблица - для каж─
дого пикселя). Он также позволяет и другой
метод - при любом угле поворота используем
одну и ту же таблицу, хранящую смещение в
текстуре и масштаб для каждого столбца.
(Столбы масштабируем как в Wolfenstein .)
Этот второй метод отнимает значительно
меньше памяти и реально применим. Сначала
предполагалось использовать его для трёх─
мерного квеста Big L, но при его разработ─
ке встал ряд трудностей, и этот код вместе
с графикой в конце концов попал в демо
New Wave 48K.
48К - это достаточно сильное ограниче─
ние. Размер текстуры пришлось ограничить
512x128 (32 килобайта), потому что для ка─
ждого столбца (путём экспериментов были
выбраны столбцы шириной 4 пикселя) надо
иметь 4 разных сдвига в текстуре (чтобы
иметь шаг в 2 пикселя).
Пояснение про размер текстуры: суть в
том, что руками сдвигать данные по горизо─
нтали медленно, поэтому надо хранить сдви─
нутые байты.Если сдвигать с шагом в 2 пик─
селя (а иначе как сохранить штриховку?),то
будет 4 сдвига. Мы не храним 2 сдвинутых
копии в одном байте (их было бы медленно
вдвигать и накладывать), а только одну.
Поэтому при ширине512 получается (512/8)*
*4(сдвигов)*hgt байтов, что при hgt=128
даёт64*4*128=32768.
Можно представить эту проекцию на рису─
нке (вид сверху):
(где-то вдали - поверхность цилиндра)
условный экран
камера,
она же центр цилиндра
Формулы были такие:
Для каждого n=-23.5..+23.5 с шагом 1
(это номер столбца) считаемx=n/24 (это
номер столбца в пределах-1..+1 ) считаем
уголa=arctg x (здесь угол зрения равен 90
градусов,иначе надо другие пределы дляx -
лучше меньше,но тогда нужно большее разре─
шение текстуры по горизонтали);
считаем масштабk=cos a (можно добавить
коэффициент, если хотим сэкономить на вы─
соте текстуры или наоборот сделать тексту─
ру точнее);
считаем координату столбца в текстуре
xtex=a*128/pi (получается -32..+32 - для
ширины 512 с шагом в 2 пикселя).
Код использовался такой:
ld d,h
ld a,(de)
exx
xor (hl)
and d ;#f0
xor (hl)
ld (bc),a
inc h
inc b
exx
inc d
ld a,(de)
exx
xor (hl)
and d ;#f0
xor (hl)
ld (bc),a
inc b
[ld a,c:add a,20:ld c,a...между знакомест]
ex af,af'
add a,e
jr nc,$+3
inc h
ex af,af'
exx
add hl,bc
Такое рисование по 2 строчки приемлемо
из-за небольшого разброса масштабов. Оно
мало того что ускоряет отрисовку, оно ещё
и позволяет меньше портить штриховки на
картинке.
Это был один из этапов борьбы за чисто─
ту картинки. Другой был связан с проблемой
растягивания по горизонтали (из-за малень─
кого разрешения текстуры). Если оставить
всё как есть, то вертикальные линии будут
дублироваться. Чтобы частично скрыть этот
дефект на имевшейся прорисованной картинке
(от Surfin' Bird ), сдвинутые копии столб─
цов (те самые, которые шириной 4 пикселя)
редактировались следующим образом:
на левой границе столбца (смотрим полу─
байты попарно):
01?? -> 10??
01?? -> 01??
на правой границе столбца:
??10 -> ??10
??10 -> ??01
Можно сделать и наоборот (для других
картинок).
* * *
Теперь выйдем в новое измерение и поду─
маем насчёт подъёма-опускания камеры.Здесь
мы опять стоим перед выбором - на какую
фигуру натянуть текстуру: цилиндр, куб или
другой многогранник, сфера... И выбор тут
гораздо труднее.
Если мы возьмём многогранник,нам придё─
тся озаботиться насчёт настоящего ЗD-движ─
ка сtexture mapping (tmap), что сводит на
нет выигрыш от неподвижной камеры (хотя...
модель мира проще).
Если цилиндр - то чем затыкать его кон─
цы? Если не затыкать,то нам нужна бесконе─
чная текстура.Или придётся ограничить углы
подъёма-опускания камеры (зенит и надир
сделать невидимыми).
Если сфера - формулы пересчёта на каж─
дый пиксель просто ужасны.
Можно рассчитывать только узлы сетки
8x8, а между ними проводить интерполяцию -
упрощённый tmap. Этот метод проверен вре─
менем,и с ним можно использовать медленные
способы расчёта, такие как:
1.Raymarching - сканирование воксельно─
го объёма с помощью маленьких шагов. Это
уже было описано в статье"О летающем сло─
не" в Info Guide #10 (по поводу интры к
#5 ). Это очень медленный метод.
2.Настоящий расчёт проекции цилиндра на
экран. Для каждой точки считаем арктангенс
и всё такое.
3.То же, что п. 2, но избавляемся от
арктангенса, делая цилиндр квадратным.
Насколько мне известно,такие мудрёности
на Спектруме делал только SaiROOs в деме
Dogma, и получилось весьма медленно даже
для того разрешения. Код не смотрел,но ри─
сковать не стал. В Nedodemo я выбрал самый
простой метод, и не зря - оказалось, что
даже он едва-едва успевал на тогдашней
компо-машине Pentagon 102ЧSL v2.2.
Самый простой метод такой - для каждого
угла подъёма камеры имеем свою таблицу.
Отрисовку на экран производим непосредст─
венно по ней. Более того, генерируем из
неё код (ld a,(hl):ld (de),a:inc d с нуж─
нымиinc/dec для h и l ). Проецировать мо─
жем на любую фигуру с осевой симметрией. Я
выбрал сферу.
Текстуры были рассчитаны на куб (сдела─
ны через ЗD-модель с 6 камерами), я перес─
читал их на сферу с помощью специально на─
писанной утилиты. Вы можете её найти в ис─
ходниках Nedodemo у меня на сайте.
Казалось бы, забили 27 страниц памяти -
куда так? Но если не генерировать код из
таблицы, то можно заметить, что таблицы
зеркально симметричны поX и попарно соот─
ветствуют друг другу поY (с отражением).
Если бы стояла задача загнать этот эффект
в128К, она была бы выполнена. А вот в 48К
- нет.48К мир существенно отличается от
мира расширенной памяти.
Другой вопрос, что делать,чтобы поднять
разрешение этого эффекта до приемлемого в
играх. К сожалению, ответа пока нет. Что
однозначно - текстура должна иметь разре─
шение, превышающее размер экрана не менее
чем в 4 раза. В Nedodemo разрешение текс─
туры 256x64 (она немного сплющена по вер─
тикали) при разрешении экрана56x61, и те─
ксели при этом видны. То есть, например,
для разрешения экрана256x128 понадобится
сферическая текстура порядка1024x256 или
куб с текстурами256x256.
Other articles: