Trójkąty - wypełnianie jednokolorowe
Aby stworzyć 3D-engine musimy się nauczyć rysować na ekranie trójwymiarowe bryły. Każda taka bryła, niezależnie od kształtu składać się będzie z płaskich ścian. Każda ściana jest wielokątem. Każdy wielokąt można podzielić na trójkąty. Dlatego bardzo ważne jest, aby mieć gotową procedurę potrafiącą wypełnić trójkąt. W tym artykule dowiesz się jedynie jak wypełnić go jednym kolorem - ale jego zrozumienie jest potrzebne do zrozumienia dalszych lekcji na temat cieniowania, teksturowania, etc...
Jak zapewne wiecie, każdy trójkąt ma dokładnie trzy wierzchołki:

Do naszych celów wierzchołki powinne być posortowane. Ten najwyższy powinien być pierwszy, a najniższy - trzeci. Lepiej od razu podam jak posortować wierzchołki, żeby ktoś do tego quicksorta nie zaciągał ;) a także dlatego, że już w kilku miejscach widziałem sortowanie nieoptymalne (np. w pliku fatmap.txt).
(zwróć uwagę na wcięcia, ostatni warunek sprawdzamy tylko wtedy, gdy warunek drugi jest prawdziwy)
Po posortowaniu wierzchołków sytuacja wygląda tak:

Trójkąt rysować będziemy liniami poziomymi. Zaczynamy od góry i posuwamy się w dół. Rysowanie składa się z dwóch części - najpierw linie od wierzchołka 1 do 2 (zielone pole), potem linie od wierzchołka 2 do 3 (żółte pole).

Narysowanie każdej linii polega na pokolorowaniu pixeli od pewnego punktu położonego na lewej krawędzi, do punktu położonego na prawej krawędzi. Dla każdego Y będziemy mieli wyliczone XL (lewy X) i XR (prawy X). Niektórzy wyliczają je na początku, jeszcze przed rysowaniem, nie ma to jednak sensu. Ja ustalam wartości XL i XR na początku i zmieniam je w każdej linii po narysowaniu poprzedniej.

Linię więc narysujemy tak:
W typowym trójkącie (nie w każdym! jest jeden wyjątek o którym trzeba pamiętać) pierwsza linia ma długość zero, ponieważ zarówno XL jak i XR są równe współrzędnej poziomej najwyższego wierzchołka - czyli X1. Potem w każdej linii lewy i prawy X zmieniają się o pewną wartość. Nazwijmy te wartości - delta_xl dla lewego X i delta_xr dla prawego X.
Te wzory trzeba zrozumieć. Delta_lx mówi nam o ile zmienia się lewy x w każdej linii. Oblicza się więc ją dzieląc różnicę X na obu końcach lewej krawędzi przez ilość linii do narysowania.
Zwróć uwagę, że powyższe wzory prawdziwe są tylko wtedy, gdy drugi wierzchołek trójkąta znajduje się po lewej stronie. Trzeba to sprawdzić i jeżeli okaże się, że jest po prawej - delty zamieniają się miejscami.
Po narysowaniu y2-y1 linii (czyli pierwszej części trójkąta), jedna z delt się zmieni. W tym przypadku będzie to lewa delta.
Jeżeli wierzchołek numer 2 był po prawej stronie - zmieni się prawa delta.
Po narysowaniu drugiej części nie zostaje już nic - bo cały trójkąt jest narysowany :-) Cały algorytm wygląda więc w przybliżeniu tak:
posortuj_wierzchołki_według_y
Napisanie dobrze całego algorytmu nie jest takie proste. Mi zajmowało zawsze cały wieczór (pisałem w czystym assemblerze). Trzeba bowiem pamiętać o wielu przypadkach, które trzeba uwzględnić. Co będzie np. gdy nie będzie dolnej lub górnej części. Wtedy np. y2-y1 będzie równe 0. I jeżeli tego nie sprawdzisz - dostaniesz dzielenie przez 0.
Najlepszy sposób na sprawdzenie czy algorytm działa w każdym przypadku, to napisanie obracającego się trójkącika. Bierzesz trzy punkty na ekranie i co klatkę obracasz je wokół środka ekranu, a następnie rysujesz trójkąt, którego są wierzchołkami.
No cóż... zostaje życzyć ci powodzenia :-) Jeżeli uda ci się napisać dobrze wypełnianie trójkąta - możesz zaczynać swoją przygodę w trójwymiarowym świecie. Już nie długo będziesz mógł tworzyć w nim naprawdę fascynujące rzeczy... powyższy materiał - bez tego może być trudniej w dalszych lekcjach.
Jak zapewne wiecie, każdy trójkąt ma dokładnie trzy wierzchołki:

Do naszych celów wierzchołki powinne być posortowane. Ten najwyższy powinien być pierwszy, a najniższy - trzeci. Lepiej od razu podam jak posortować wierzchołki, żeby ktoś do tego quicksorta nie zaciągał ;) a także dlatego, że już w kilku miejscach widziałem sortowanie nieoptymalne (np. w pliku fatmap.txt).
jeżeli y1>y2 to
Zamień(1,2)
jeżeli y2>y3 to
Zamień(2,3)
jeżeli y1>y2 to
Zamień(1,2)
Zamień(1,2)
jeżeli y2>y3 to
Zamień(2,3)
jeżeli y1>y2 to
Zamień(1,2)
(zwróć uwagę na wcięcia, ostatni warunek sprawdzamy tylko wtedy, gdy warunek drugi jest prawdziwy)
Po posortowaniu wierzchołków sytuacja wygląda tak:

Trójkąt rysować będziemy liniami poziomymi. Zaczynamy od góry i posuwamy się w dół. Rysowanie składa się z dwóch części - najpierw linie od wierzchołka 1 do 2 (zielone pole), potem linie od wierzchołka 2 do 3 (żółte pole).

Narysowanie każdej linii polega na pokolorowaniu pixeli od pewnego punktu położonego na lewej krawędzi, do punktu położonego na prawej krawędzi. Dla każdego Y będziemy mieli wyliczone XL (lewy X) i XR (prawy X). Niektórzy wyliczają je na początku, jeszcze przed rysowaniem, nie ma to jednak sensu. Ja ustalam wartości XL i XR na początku i zmieniam je w każdej linii po narysowaniu poprzedniej.

Linię więc narysujemy tak:
dla każdego x od XL do XR
pokoloruj_pixel(x,y)
W typowym trójkącie (nie w każdym! jest jeden wyjątek o którym trzeba pamiętać) pierwsza linia ma długość zero, ponieważ zarówno XL jak i XR są równe współrzędnej poziomej najwyższego wierzchołka - czyli X1. Potem w każdej linii lewy i prawy X zmieniają się o pewną wartość. Nazwijmy te wartości - delta_xl dla lewego X i delta_xr dla prawego X.
delta_xl=(x2-x1)/(y2-y1)
delta_xr=(x3-x1)/(y3-y1)
delta_xr=(x3-x1)/(y3-y1)
Te wzory trzeba zrozumieć. Delta_lx mówi nam o ile zmienia się lewy x w każdej linii. Oblicza się więc ją dzieląc różnicę X na obu końcach lewej krawędzi przez ilość linii do narysowania.
Zwróć uwagę, że powyższe wzory prawdziwe są tylko wtedy, gdy drugi wierzchołek trójkąta znajduje się po lewej stronie. Trzeba to sprawdzić i jeżeli okaże się, że jest po prawej - delty zamieniają się miejscami.
Po narysowaniu y2-y1 linii (czyli pierwszej części trójkąta), jedna z delt się zmieni. W tym przypadku będzie to lewa delta.
delta_lx=(x3-x2)/(y3-y2)
Jeżeli wierzchołek numer 2 był po prawej stronie - zmieni się prawa delta.
Po narysowaniu drugiej części nie zostaje już nic - bo cały trójkąt jest narysowany :-) Cały algorytm wygląda więc w przybliżeniu tak:
posortuj_wierzchołki_według_y
xl=x1
xr=x1
oblicz_deltę (lewą,1,2)
oblicz_deltę (prawą,1,3)
narysuj_linie_od_y1_do_y2
oblicz_deltę (lewą,2,3)
narysuj_linie_od_y2_do_y3
xr=x1
oblicz_deltę (lewą,1,2)
oblicz_deltę (prawą,1,3)
narysuj_linie_od_y1_do_y2
oblicz_deltę (lewą,2,3)
narysuj_linie_od_y2_do_y3
Napisanie dobrze całego algorytmu nie jest takie proste. Mi zajmowało zawsze cały wieczór (pisałem w czystym assemblerze). Trzeba bowiem pamiętać o wielu przypadkach, które trzeba uwzględnić. Co będzie np. gdy nie będzie dolnej lub górnej części. Wtedy np. y2-y1 będzie równe 0. I jeżeli tego nie sprawdzisz - dostaniesz dzielenie przez 0.
Najlepszy sposób na sprawdzenie czy algorytm działa w każdym przypadku, to napisanie obracającego się trójkącika. Bierzesz trzy punkty na ekranie i co klatkę obracasz je wokół środka ekranu, a następnie rysujesz trójkąt, którego są wierzchołkami.
No cóż... zostaje życzyć ci powodzenia :-) Jeżeli uda ci się napisać dobrze wypełnianie trójkąta - możesz zaczynać swoją przygodę w trójwymiarowym świecie. Już nie długo będziesz mógł tworzyć w nim naprawdę fascynujące rzeczy... powyższy materiał - bez tego może być trudniej w dalszych lekcjach.
Autorem tekstu jest:
Jacek Popławski
Materiał dodany przez użytkownika: alphan
