Inferno #07
31 мая 2005

Gamedev - 3D проецирование пола/трассы в играх.

3D проецирование пола/трассы
   В Wolf'2004  пола нет, а в существующих
на ZX гонках  он хотя и есть, но нечестный 
(по  нему нельзя ездить поперёк трассы и в 
обратном направлении). Настоящий пол нужно 
получать  перспективным  проецированием на 
экран картинки (трассы) достаточно большо─ 
го размера. 

Newart> 
   Игровое окно занимает,допустим, 160 пи-
кселей, половину  окна  занимает  спроеци-
рованный  ландшафт, длина его, наверно, до
проецирования раза в 3 больше,чем видно на
экране  после  проецирования. Объясни, как
ты предлагаешь сделать без ротации...
 Alone Coder> 
   Ротация  будет, но  в процессе переноса
 графики в chunkmap. Т.е. 2 прохода: 
   1. rotate;
  2. вывод чанков.
Newart> 
   А проецирование  будет  во время вывода
чанок?
 Alone Coder> 
    Проецирование во время ротации.
   Пусть  высота земли = 80  пикселей ( 40
чанков). Расстояния,на которых видны выво─ 
димые горизонтальные линии, относятся друг 
к другу как 40/40, 40/39, 40/38 и т.д.,по─ 
следняя  линия - 40/1. Допустим, что карта 
имеет размер, ну,хотя бы 256x512 пикселей. 
Пусть  4 самых задних линии земли не видны 
(серые), а видим мы на расстояние не более 
1/3 карты (зависит от высоты наблюдателя). 
Тогда  при чанках 2x4 на самых ближних ли─ 
ниях  будут различимы пиксели текстуры, но 
получатся  они размером не более 2 чанков, 
если я не обсчитался. Т.е. ОЧЕHЬ ДАЖЕ тер- 
 пимо... 
   Внутри  каждой горизонтальной линии эк─
рана  мы  движемся по текстуре равномерно, 
равными  приращениями. Перед выводом линии 
нужно только рассчитать её начало на текс─ 
туре и вектор движения по текстуре (и то,и 
другое можно высчитать по таблицам). 
 

   Математика тут ничего из себя не предс─
 тавляет. 
   Обозначим  координаты  игрока через x0,
y0, а его угол поворота - через a. Условно 
определим  ось  z от середины экрана вниз, 
 масштаб - любой. 
   Тогда расстояние по карте до точки, ко─
торую нужно вывести в середине горизонтали 
z, равно: d(z)=k1/z, где  k1 - некий коэф─ 
фициент (он  зависит  от высоты игрока над 
 поверхностью). 
   Координаты этой точки на карте, если их
отсчитывать от координат игрока, равны: 
 cx(z,a)=d(z)*cos(a); cy(z,a)=d(z)*sin(a). 
   Шаг,с которым мы будем проходить карту,
рисуя  горизонталь z, равен: step(z)=k2/z, 
где k2 - некий другой коэффициент (отноше─ 
ние  k1/k2 определяет прямоугольную "вытя─ 
 нутость" изображения). 
   Составляющие этого шага по x и y равны:
stepx(z,a)=step(z)*sin(a); 
 stepy(z,a)=-step(z)*cos(a). 
   Тогда понятно,что левая точка нашей ли─
нии z на карте будет иметь координаты: 
leftx(z,a)=cx(z)-width*stepx(z,a); 
 lefty(z,a)=cy(z)-width*stepy(z,a). 
   То  есть  вместо  математики может быть
просто таблица значений stepx,stepy,leftx, 
lefty размером 36*64 (остальные 192 угла a 
можно свести  к этим 64 углам простыми об─ 
менами координат и сменами их знаков).Пос─ 
кольку эти числа 16-битные,то таблица зай─ 
мёт 18 килобайт (можно  разложить по стра─ 
ничкам - особая скорость здесь не нужна).А 
все  вычисления "на лету" сведутся к прос─ 
тому прибавлению координат игрока (x0, y0) 
 к прочитанным из таблицы координатам. 
   Главное - разбиение карты на "знакомес─
та" (тайлы). Предположим, что  тайл  равен 
16(Y)*8(X) текселей (текстурных элементов, 
пикселей). Храниться  они будут по адресам 
%0110yyyyxxxttttt, где yyyy,xxxx - коорди- 
наты  внутри  тайла, ttttt - номер  тайла. 
Тогда карта будет 16*128=2048(Y) на 8*256= 
 =2048(X). 
   Проецирование  идёт  в  чанковый  буфер
(потом можно будет накладывать спрайты). 

 width=24 ;CHRS 
       (DUP width)
         ADD IX,DE ;Y
         EXX
         ADD HL,BC ;X
         LD E,H  ;X
         LD D,HX ;Y
        (set 7,d) ;чтобы не зашкал.за карту
         LD A,(DE) ;номер тайла, стоящего в
                          ;этом месте карты
         XOR L ;мл.байт X (внутри тайла)
         AND #1F
         XOR L ;A=%xxxttttt
         EXX
         LD L,A
         LD A,LX ;мл.байт Y (внутри тайла)
         RRA
         SCF
         RRA
         SCF
         RRA
         OR A
         RRA   ;A=%0110yyyy
         LD H,A ;HL=адрес текселя в тайле
        LD B,(HL) ;цвет чанка
 ;и ещё раз: 
         ADD IX,DE ;Y
         EXX
         ADD HL,BC ;X
         LD E,H  ;X
         LD D,HX ;Y
        (set 7,d) ;чтобы не зашкал.за карту
        LD A,(DE) ;номер тайла, стоящего в
                          ;этом месте карты
         XOR L ;мл.байт X (внутри тайла)
         AND #1F
         XOR L ;A=%xxxttttt
         EXX
         LD L,A
         LD A,LX ;мл.байт Y (внутри тайла)
         RRA
         SCF
         RRA
         SCF
         RRA
         OR A
         RRA   ;A=%0110yyyy
         LD H,A ;HL=адрес текселя в тайле
         LD C,(HL) ;цвет чанка
         PUSH BC ;кладём 2 чанка в чанкмэп
      (EDUP)
 

    Точность расчётов = 1/8 текселя.
    Вывод чанков на экран:
       (DUP width)
         POP HL ;цвета двух чанков:
                       ;%1111aaa1,%1111bbb1
         LD A,(HL)
         LD (BC),A
         LDD ;DE=BC+256 (или наоборот)
      (EDUP)
 

   Можно чередовать вывод чанков с проеци─
рованием  после  каждой строчки картинки - 
но тогда без спрайтов на экране.Хотя можно 
 выводить их хитро, тоже по строчке. 
   Размер  чанкмэпа (включая верхнюю поло─
вину, где карта не рисуется): 
 48(2*width)*80(hgt)=3840. 
   Памяти не осталось, поэтому можно испо─
льзовать 2-й экран,а можно уменьшить карту 
по Y  в два раза (до размера  странички) - 
добавить ещё  SET 6,D. Вообще-то эти SET - 
дело  вкуса, можно просто не давать игроку 
приближаться к границе карты. 

A. Coder 




Темы: Игры, Программное обеспечение, Пресса, Аппаратное обеспечение, Сеть, Демосцена, Люди, Программирование

Похожие статьи:
Living on IRC - Посвящается стойким фанатам Спектрума.
Тема ОС - Bul(dez)er научился кодить и сменил свое мнение об ОС на Спектруме.
ХАЙ-TECН - Cёдня мы нe будeм ничё тут пилить, свeрлить и гнуть,a зaймёмся кoe-чeм другим!

В этот день...   18 ноября