Płaskie 3D

Ostatnim i często niedocenianym przez twórców gier i grafiki trójwymiarowej etapem tworzenia sceny 3D jest rasteryzacja - a od niej też zależy to, co ujrzymy na ekranie monitora

W poprzednich częściach cyklu o sprzętowym generowaniu grafiki 3D (patrz: $(LC123938:Trójwymiarowa rewolucja)$, $(LC126772:Fotorealizm 3D)$, i $(LC131822:Sposób na światło)$) przedstawiliśmy, w jaki sposób karta graficzna tworzy szkielet sceny, nakłada na nią tekstury i na końcu ją oświetla. Teraz przyszedł czas na ostatni etap realizowany w strumieniu graficznym, a mianowicie na proces przygotowania gotowej sceny trójwymiarowej do wyświetlenia jej na ekranie monitora. Później pozostaje już tylko wysłać obraz do wyświetlacza. W literaturze wymienione operacje nazywa się rasteryzacją. Termin ten nie do końca oddaje jednak istotę tego, co się dzieje w ostatniej fazie generowania grafiki trójwymiarowej.

W dużym uproszczeniu można powiedzieć, że ideą procesu rasteryzacji, wykonywanego podczas generowania grafiki 3D, jest zamiana gotowej sceny trójwymiarowej na zbiór pikseli (bitmapę), które wyświetlone zostaną na ekranie monitora. Co więcej, każdy punkt rysunku odpowiadać będzie jednemu pikselowi na monitorze w zadanej rozdzielczości. Operacje rasteryzacji wykonuje wyspecjalizowana jednostka (rasteryzator), znajdująca się w każdym, nawet najprostszym i najstarszym akceleratorze 3D.

Gwoli ścisłości należy też powiedzieć, że rasteryzacja nie dotyczy tylko grafiki 3D, ale również 2D – np. dostosowywania dowolnego płaskiego obrazu (np. tekstu czy linii) do wyświetlenia na monitorze. W trakcie dopasowywania wszystkie obiekty, takie jak np. linie i okręgi, muszą zostać narysowane za pomocą ograniczonej liczby kwadratowych pikseli monitora. Karta graficzna rozwiązuje więc problem, które punkty i z jaką intensywnością należy zapalić, by to, co będziemy oglądać, jak najwierniej przypominało zadane krzywizny. W najprostszych przypadkach algorytm rasteryzujący zapala piksele leżące najbliżej rysowanej krzywej. Podobne problemy z zapalaniem barwnych punktów trzeba rozwiązać też przy odwzorowywaniu kolorów.

1a. Test głębokości, czyli do czego służy Z-bufor

Wstępnym etapem przy rasteryzacji grafiki 3D jest „zgubienie” niepotrzebnego już trzeciego wymiaru generowanej sceny. Jak wiadomo, w obrazie trójwymiarowym każdemu punktowi przyporządkowane są trzy współrzędne: X, Y, Z. Przeniesienie dwóch pierwszych wartości na ekran jest proste, gdyż wyznaczają one pozycję obiektu w pionie i poziomie. Na przykład przy rozdzielczości 1280×1024 piksele współrzędna X ograniczona jest do 1280, a Y do 1024 punktów i do takich rozmiarów od początku dopasowywana była tworzona przez kartę scena 3D. Współrzędna Z (głębia), której nie da się przedstawić na dwuwymiarowym monitorze, określa odległość przedmiotów od płaszczyzny ekranu. Zazwyczaj w grach i programach do tworzenia grafiki 3D wykorzystuje się 16-, 24- lub 32-bitową głębię. W tym pierwszym przypadku daje to 65 536, a ostatnim już 4 294 967 296 możliwych pozycji obiektu.

Aby wyznaczyć, czy dany piksel należący do przedmiotu zostanie narysowany, przeprowadza się tzw. test głębokości (ang. depth buffering). Ma on na celu sprawdzenie głębi (współrzędnej Z) dla każdego obiektu i wszystkich należących do niego punktów. Następnie podejmowana jest decyzja, czy dany piksel powinien zostać narysowany. Innymi słowy test głębokości sprawdza położenie każdego punktu i postanawia, czy nowo analizowany piksel znajduje się bliżej obserwatora niż ten poprzednio umieszczony w tym samym miejscu ekranu o współrzędnych X oraz Y.

Test głębokości można wykonywać w różny sposób – zarówno programowo (aplikacja sama analizuje położenie punktów zgodnie z algorytmem wymyślonym przez programistę), jak i sprzętowo. W kartach graficznych etap ten realizowany jest za pomocą dwóch wspieranych hardware’owo technik: metody Z-bufora (ang. Z-buffer) i renderingu kafelkowego (ang. tile rendering – patrz: ramka wyżej).

Najprostszym sposobem na przeprowadzenie testu głębokości jest narysowanie po kolei wszystkich punktów sceny 3D od najgłębszej do najpłytszej warstwy. Oczywiście metoda ta jest najbardziej pracochłonna z możliwych, gdyż na ekranie odwzorowywany jest każdy piksel, nawet w sytuacji, gdy na gotowym obrazie i tak nie będzie go widać. Aby ominąć ten problem i przyspieszyć generowanie grafiki trójwymiarowej, twórcy programów 3D, takich jak np. 3ds max czy Maya 3D, stosują własne algorytmy eliminacji niewidocznych punktów, m.in. BSP (Binary Space Partitioning – binarne dzielenie przestrzeni) lub tzw. technikę portali, odcinającą zasłonięte elementy sceny.

Oprócz metod software’owych bezpośrednio w karty 3D wbudowane są niezależne sprzętowe mechanizmy odciążające jednostkę rasteryzującą. Co ważne, do swojego działania nie potrzebują one żadnej ingerencji programisty. Innymi słowy osoba pisząca program nie musi w ogóle pilnować, jak karta przeprowadzi testy głębokości – stanie się to automatycznie.

Jak już wspomniałem, najczęściej stosowaną techniką zarówno w akceleratorach firmy ATI, jak i nVidii jest wykorzystanie Z-bufora. Podczas zamiany trójwymiarowej sceny na obraz dwuwymiarowy w RAM-ie akceleratora wydziela się obszar pamięci (matrycę) odpowiadający swoją wielkością rozdzielczości ekranu, a „głębokością” 16, 24 lub 32 bitom w zależności od dokładności współrzędnej Z. Ten duży objętościowo fragment pamięci nosi właśnie nazwę Z-bufora i w nim przeprowadza się analizę głębokości dla wszystkich znajdujących się na scenie obiektów.

Jak zatem działa ów Z-bufor? Otóż w czasie rasteryzacji każdego z trójkątów tworzących szkielet sceny z nałożonymi na niego teksturami i mapą oświetlenia należy podjąć decyzję o tym, czy wybrany punkt znajduje się bliżej obserwatora (będzie wyświetlony) czy też jest zasłonięty przez inną bryłę i należy go zignorować. W Z-buforze znajdą się zatem informacje o usytuowaniu trójkątów (a raczej położeniu ich rzutów perspektywicznych) składających się na scenę 3D. Mówiąc ściślej, dane umieszczane w Z-buforze dotyczą punktów wypełniających i tworzących każdy z analizowanych trójkątów – np. zapisuje się tam dane o 17 punktach, z których składa się pierwszy trójkąt. Informacje te są następnie sukcesywnie zamieniane na dane o pikselach ekranu, a mówiąc dokładniej, o tym, jaki ostatecznie kolor ma mieć na ekranie punkt o współrzędnych X i Y (te informacje gromadzi się w buforze ramki).

Do Z-bufora trafiają zatem najpierw współrzędne X, Y, Z punktów należących do pierwszego analizowanego trójkąta. Gdy rasteryzowany jest drugi trójkąt, przed umieszczeniem informacji o nim w buforze ramki porównuje się jego współrzędne z wartościami zapamiętanymi w Z-buforze. Kiedy współrzędne X, Y się pokrywają, sprawdza się współrzędną Z. Jeśli nowy punkt ma wartość niższą (0 oznacza najpłytszą warstwę), jest on „rysowany” w buforze ramki. W przeciwnym wypadku pozostają tam „zapalone” piksele pochodzące z poprzedniego trójkąta. Cały proces powtarzany jest dla każdego obiektu generowanej sceny 3D.

0
Zamknij

Choć staramy się je ograniczać, wykorzystujemy mechanizmy takie jak ciasteczka, które pozwalają naszym partnerom na śledzenie Twojego zachowania w sieci. Dowiedz się więcej.