Из журнала Scenergy #2, Новгород, 2000
;-----------------------------------------
;-TEXTURE MAPPING- ESPECIALLY 4 SCENERGY
;-----------------------------------------
(C) 1999 SaiR00S/EI
Суть линейного текстурного мэппинга
заключается в линейной интерполяции
координат полигона и соответствующим им
текстурных координат.
В качестве полигона чаще всего
выбирается треугольник, хотя описанный
ниже алгоритм подходит для любого
полигона.
Итак, полигоном является треугольник,
все вершины которого имеют пары координат
(X,Y) и связанные с ними текстурные
координаты (U,V). По полигону мы будем
двигаться сверху-вниз и слева-направо ,
т.е при движении сверху-вниз мы будем
увеличивать на каждом вертикальном шаге
координату Y треугольника при
одновременной линейной интерполяции
координаты X и текстурных координат (в
итоге получится контур полигона и
соответствующий ему контур треугольника в
текстуре), а при движении слева-направо,
увеличивая координату X-координату от
левой границы контура до правой на
единицу, проводим линейную интерполяцию по
текстуре и ставим в координату Xi,Yj
значение цвета из текстуры по координатам
Up,Vq.
Первое , что необходимо сделать - это
отсортировать координаты треугольника
вmeсте с текстурными координатами в
порядке возрастания координаты Y, т.е.
If vert1.y > vert2.y then
swap (vert1,vert2);
If vert2.y > vert3.y then
swap (vert2,vert3);
If vert3.y > vert1.y then
swap (vert3,vert1);
Или (лексика STORM'a):
LD HL,(VERT1); Берем X,Y координа-
LD DE,(VERT2); ты треугольника
LD BC,(VERT3);
EXX
LD HL,(VERT1+2); Берем текстурные
LD DE,(VERT2+2); координаты U,V
LD BC,(VERT3+2);
EXX
LD A,D
CP H
JR NC,NOSWAP1
EX DE,HL
EXX
EX DE,HL
EXX
NOSWAP1 LD A,B
CP H
JR NC,NOSWAP2
LD A,L,L,C,C,A
LD A,H,H,B,B,A
EXX
LD A,L,L,C,C,A
LD A,H,H,B,B,A
EXX
NOSWAP2 LD A,B
CP D
JR NC,NOSWAP3
LD A,E,E,C,C,A
LD A,D,D,B,B,A
EXX
LD A,E,E,C,C,A
LD A,D,D,B,B,A
EXX
NOSWAP3 LD (VERT1),HL
LD (VERT2),DE
LD (VERT3),BC
EXX
LD (VERT1+2),HL
LD (VERT2+2),DE
LD (VERT3+2),BC
EXX
В результате получается картина,
изображенная на рисунке. В данном случае
точка перегиба находится слева,
соответственно, в левой половине
треугольника имеем 2 грани, а в правой -
одну.
Ha рисунке:
H - максимальная высота треугольника
H1 - высота ребра (vert1,vert2);
H2 - высота ребра (vert2,vert3);
W - наибольшая ширина треугольника
треугольника по X. Определяется
она следующим образом:
t=(vert2.y-vert1.y)/(vert3.y-vert1.y)
w=(vert1.x+t*(vert3.x-vert1.x))-vert2.x
Если H и/или W равны нулю, то
треугольник рисовать не нужно.
Далее определяется с какой стороны
находится точка перегиба в треугольнике.
Делается это проверкой знака величины W.
Если эта величина положительна, то точка
перегиба - слева, отрицательна - справа.
If w>0 then "point" on left
else "point" on right
Затем проводим линейную интерполяцию
координаты X треугольника и текстурных
координат U,V. Интерполяцию можно
проводить по нижеприведенным формулам или
по Брезенхему - кому как нравится,но
второй вариант быстрее (хотя, при малом
количестве полигонов, что мы имеем на
Спектруме, это практически не заметно).
Итак, если точка перегиба слева (W>0),
то нужно отрисовать две грани слева и одну
справа:
Строим левую сторону треугольника:
h1=vert2.y-vert1.y
DeltaLeftX1=(vert2.x-vert1.x)/h1
DeltaLeftU1=(vert2.u-vert1.u)/h1
DeltaLeftV1=(vert2.v-vert1.v)/h1
h2=vert3.y-vert2.y
DeltaLeftX2=(vert3.x-vert2.x)/h2
DeltaLeftU2=(vert3.u-vert2.u)/h2
DeltaLeftV2=(vert3.v-vert2.v)/h2
X:=vert1.x;
For i=0 to h1 do
Begin
TableLeftX[i]:=X;
TableU[i]:=U;
TableV[i]:=V;
X:=X+DeltaLeftX;
U:=U+DeltaLeftU;
V:=V+DeltaLeftV;
End;
For i=h1 to h2 do
Begin
TableLeftX[i]:=X;
TableU[i]:=U;
TableV[i]:=V;
X:=X+DeltaLeftX2;
U:=U+DeltaLeftU2;
V:=V+DeltaLeftV2;
End;
Строим правую сторону треугольника:
h=vert3.y-vert1.y;
DeltaRightX=(vert3.x-vert1.x)/h;
For i=0 to h do
Begin
TableRightX[i]:=X;
X:=X+DeltaRightX;
End;
Здесь:
TableLeftX[] - таблица, содержащая X
координаты левой поло-
вины треугольника;
TableRightX[]- то же для правой поло-
вины;
ТableU[] - таблица, содержащая U
координаты левой поло-
вины треугльника;
TableV[] - то же для V-координаты
DeltaLeftX - константа интерполяции
(на ZX должна считать-
ся с fixed point 8.8);
DeltaRightX - то же.
Если же точка перегиба находится справа
(W<0), то все аналогично, только слева
отрисовываем одно ребро треугольника , а
справа - два.
Далее определяем шаги по текстуре ,
которые являются постоянными для всего
полигона (на ZX будем считать их с fixed
point 8.8, причем со знаком!):
DeltaU=(t*(u3-u1)+(u1-u2))/w
DeltaV=(t*(v3-v1)+(v1-v2))/w
Далее непосредственно рисуем полигон:
i:=0;
For Y:=vert1.y to (vert1.y+H) do
Begin
U:=TableU[i];
V:=TableV[i];
For X:=TableLeftX[i] to TableRigtX[i] do
Begin
{ставим точку в координату (X,Y) цвета
из текстуры по координате (U,V)}
PutPixel(X,Y,Texture[U,V])
X:=X+1;
U:=U+DeltaU;
V:=V+DeltaV
End;
i:=i+1
End;
Внутренний цикл будет выглядеть
следующим образом (кстати, возможно
быстрее...):
LD A,H; V-координата в текстуре
ADD HL,DE; вычисляем следующую ко-
; ординату V
EXX
LD B,A
LD C,H ; U-координата в текстуре
ADD HL,DE; вычисляем следующую ко-
; ординату U
LD A,(BC); берем тексель
EXX
LD (BC),A; помещаем тексель в бу-
; фер
INC C ; увеличиваем X-координа-
; ту
Следует напомнить, что все (почти)
вычисления проводятся с fixed point 8.8,
например:
HL=H.L, т.е H содержит целую часть
числа, а L - дробную.
Ну вот, вроде и все, удачи в кодинге.