teksturowanie obiektów z wykorzystaniem reprogramowalnych
TRANSCRIPT
Wydział Informatyki
Politechnika Szczecińska
Praca magisterska
Teksturowanie obiektów
z wykorzystaniem
reprogramowalnych modułów do
obliczania cieniowania
Daniel Kos
promotor: dr inż. Radosław Mantiuk
Szczecin 2003
2
Spis treści
1. Wstęp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
2. Proces teksturowania . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
2.1. Miejsce procesu teksturowaniu w potoku przetwarzania grafiki
trójwymiarowej . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
2.2. Definicja tekstury . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
2.3. Proces nakładania tekstury . . . . . . . . . . . . . . . . . . . . . . . . . 8
2.4. Rodzaje tekstur . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
2.4.1. Tekstury rastrowe . . . . . . . . . . . . . . . . . . . . . . . . . . 15
2.4.2. Tekstury proceduralne . . . . . . . . . . . . . . . . . . . . . . . 21
2.4.3. Przykłady tekstur proceduralnych . . . . . . . . . . . . . . . . . 23
2.5. Sprzętowa realizacja procesu teksturowania . . . . . . . . . . . . . . . . 27
2.5.1. Architektura współczesnych kart graficznych . . . . . . . . . . . 27
2.5.2. Pixel i Vertex Shader . . . . . . . . . . . . . . . . . . . . . . . . 29
2.5.3. Zasada działania Vertex Shader’a . . . . . . . . . . . . . . . . . 29
2.5.4. Zasada działania Pixel Shader’a . . . . . . . . . . . . . . . . . . 31
3. Przegląd implementacji programów Pixel i Vertex Shadera . . . . . . 37
3.1. Tekstury uzyskiwane metodą bump mappingu . . . . . . . . . . . . . . 37
3.2. Tekstury powstałe w wyniku przekształceń afinicznych . . . . . . . . . . 37
3.3. Tekstury generowane za pomocą gotowych wzorów . . . . . . . . . . . . 38
3.4. Tekstury „rysowane ołówkiem” . . . . . . . . . . . . . . . . . . . . . . . 39
3.5. Tekstury generowane na podstawie fluktuacji światła . . . . . . . . . . . 39
3.6. Tekstury oparte na funkcji szumu . . . . . . . . . . . . . . . . . . . . . 40
3.7. Tekstury fraktalne . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
3.8. Tekstury uzyskiwane drogą symulacji reakcji dyfuzji . . . . . . . . . . . 41
4. Implementacja wybranych algorytmów teksturowania . . . . . . . . . 43
4.1. Generator szumu Perlin’a . . . . . . . . . . . . . . . . . . . . . . . . . . 43
4.2. Generator cząsteczek . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
4.3. Generator komórek . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
5. Analiza wydajnościowa procesu teksturowania . . . . . . . . . . . . . . 58
5.1. Środowisko i procedura testowa . . . . . . . . . . . . . . . . . . . . . . . 58
5.2. Wyniki testów . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
6. Podsumowanie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62
Literatura . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
3
1. Wstęp
Coraz więcej wymaga się od graficznych systemów czasu rzeczywistego. Gra-
cze żądają realistycznie wyglądających gier, twórcy efektów specjalnych i różnego
rodzaju animacji domagają się „wiernego podglądu” swojej pracy w czasie rzeczy-
wistym, żeby móc na bieżąco korygować wszelkie błędy czy to związane z ruchem
poszczególnych przedmiotów na scenie, czy też mimice tworzonych postaci.
Większy realizm w systemach czasu rzeczywistego osiąga się głównie poprzez:
— użycie obiektów o zwiększonej liczbie wielokątów1
— stosowanie większej ilości tekstur2 i zwiększania ich dokładności (rozdzielczo-
ści).
Zwiększanie chociażby jednego z wymienionych czynników wymaga coraz sil-
niejszych procesorów graficznych. Im więcej wielokątów na przetwarzanej scenie3,
tym wydajniejsza musi być jednostka przetwarzania geometrii, im większe tek-
stury, tym więcej pamięci musi mieć do dyspozycji procesor graficzny. Ponieważ
opracowanie i produkcja nowych rozwiązań sprzętowych jest kosztowna, próbuje
się wprowadzać różnego rodzaju techniki optymalizacyjne. I tak - dla geometrii
sceny opracowano szereg algorytmów próbujących zmniejszyć liczbę wielokątów
wchodzących w jej skład przy minimalnym uszczerbku na jakości wyświetlanej
grafiki. Dla tekstur opracowano bezstratne algorytmy kompresujące takie jak
DXTC czy też FXT1. Jednakże odkąd (rok 1998) pojawiły się karty graficz-
ne wyposażone w tzw. szadery, dzięki którym możliwa jest ingerencja w potok
sprzętowego przetwarzania geometrii i rasteryzacji wielokątów, realnym stało się
użycie tekstur proceduralnych4 generowanych w czasie rzeczywistym. O ile użycie
klasycznych tekstur rastrowych (powstałych jako skan, ręcznie rysowany obrazek,
lub w wyniku „działania matematyki”5) jest bardzo powszechne, to używanie
dynamicznie generowanych tekstur proceduralnych jest sporadyczne. Jak będzie
można się przekonać w dalszej części tej pracy, posiadają one wiele cennych zalet,
lecz niestety nie pozostają bez wad. Na ile te zalety i wady mają wpływ na
realizm generowanej grafiki, a ile na wydajność systemu wizualizacji postaram
się odpowiedzieć w dalszej części lektury.
Celem niniejszej pracy jest ocena wydajności i przydatności procesu teksturo-
1 podstawowe prymitywy tworzące obiekty trójwymiarowe, najczęściej trójkąt, czworokąt2 przeważnie dwuwymiarowa mapa bitowa3 zbiór obiektów 3D tworzących określoną kompozycję4 patrz rozdział 3.25 tekstura proceduralna nie generowana w czasie rzeczywistym
4
wania proceduralnego przy użyciu aktualnie dostępnych procesorów graficznych
przeznaczonych dla masowego odbiorcy1, w szczególności poznanie opowiedzi na
następujące pytania:
1. Jakie nowe możliwości niesie za sobą zastosowanie teksturowania procedural-
nego?
2. Jakie zalety w stosunku do tradycyjnych technik teksturowania posiada tek-
sturowanie proceduralne?
3. Na ile obecnie dostępne technologie pozwalają wykorzystać tą technikę?
4. Jaką wydajność oferują dzisiejsze procesory grafiki w zakresie wykorzystania
tekstur proceduralnych?
5. Jaka przyszłość rysuje się przed użyciem tekstur proceduralnych?
Pracę podzieliłem na następujące rozdziały:
Rozdział 2 omawia wszystko co jest związane z teksturowaniem, począwszy od
wiadomości ogólnych związanych z grafiką trójwymiarową takich jak etapy
potoku graficznego, poprzez definicje tekstur rastrowych i proceduralnych, aż
do sposobów nakładania tekstur na wielokąty. Rozdział ten omawia także
sprzętową realizację procesu teksturowania oraz jednostki cieniowania pixel i
vertex shader.
Rozdział 3 zawiera implementację trzech wybranych metod teksturowania przy
zastosowaniu technologii Pixel i Vertex Shader’a.
Rozdział 4 zajmuje się analizą wydajnościową programów z rodziału 3.
Rozdział 5 to posumowanie i określenie celów na przyszłość.
1 geforce (3, 4, FX), readeon (8500 i wyżej)
5
2. Proces teksturowania
2.1. Miejsce procesu teksturowaniu w potoku przetwarzania grafiki
trójwymiarowej
Żeby lepiej zrozumieć proces teksturowania warto przyjrzeć się całej ścieżce
przetwarzania grafiki 3D. Klasyczny potok przetwarzający składa się z następu-
jących faz (rysunek 1).
Rysunek 1. Potok przetwarzania grafiki trójwymiarowej
1. Przekształcenia modelowania - dokonywanie przekształceń w przestrzeni
obiektów6. Na tym etapie każdy obiekt zostaje przeskalowany, przesunięty i
obrócony. Naturalnie mogą tu wystąpić inne rodzaje przekształceń np.: od-
chylenie w lewo, „pofalowanie” lub inne przekształcenia deformujące.
6 lokalny układ współrzędnych obiektu, którego punkt (0,0) znajduje się przeważnie w
środku obiektu
2.2 Definicja tekstury 6
2. Obcinanie przez bryłę widzenia. Ponieważ urządzenie wyświetlające ma
ograniczone rozmiary dokonuje się obcinania sceny 3D do tzw. bryły widzenia7
której wymiary określa rzut wirtualnej kamery. Tak przekształcone wierzchoł-
ki 3D można teraz „bezpiecznie” przekształcić na współrzędne 2D.
3. Rzut na płaszczyznę rzutowania - zobrazowanie obiektu 3D na urządze-
niu wyświetlającym. Najczęściej dokonywanym rzutowaniem jest rzutowanie
perspektywistyczne i równoległe.
4. Rasteryzacja wielokątów. Tutaj następuje rysowanie otrzymanych wielo-
kątów 2D. Albo wypełnieia się je określonym kolorem albo nakłada teksturę.
Czasami też rysuje się jedynie same kontury (widać wtedy „szkielet” sceny).
Uwzglęnia się przy tym oświetlenie i stosuje odpowiednie metody cieniowania
(cieniowane płaskie, gourauda, cieniowanie „per-pixel” (phong)). Można też
stosować dodatkowe efekty takie jak bump mapping czy emboss.
5. Obraz finalny. Po narysowaniu wszystkich wielokątów można uzyskany ob-
raz wyświetlić na monitorze.
Jak wynika z powyższego rysunku proces teksturowania dokonuje się w jednym
z końcowych etapów potoku graficznego. Ma on miejsce po dokonaniu wszelkich
możliwych transformacji w przestrzeni 3D i wyznaczeniu współrzędnych w ukła-
dzie 2D. Jest to jeden z najbardziej czasochłonnych etapów potoku 3D.
2.2. Definicja tekstury
Nakładanie tekstur (ang. texture mapping) to jeden z podstawowych efektów
stosowanych w grafice trójwymiarowej. Dzięki niemu bezbarwne zarysy obiek-
tów stają się realistycznymi przedmiotami. Zamiast modelować skomplikowane
obiekty aż do najdrobniejszych szczegółów, co pochłania dużo czasu i miejsca w
pamięci, proste, bezbarwne bryły geometryczne pokrywa się dwuwymiarowymi
bitmapami nadając im żądany wygląd. Przykład, aby przedstawić na ekranie
wieżowiec widziany z zewnątrz, wystarczy zwykły prostopadłościan i po jednej
teksturze do zrzutowania na każdą z pięciu ścian budynku (jeśli chcemy by ściany
różniły się). Inny przykład obiektu obłożonego teksturą przedstawia rysunek 4.
Tekstura jest to n-wymiarowa mapa bitowa powstała w wyniku skanowania ob-
razów rzeczywistych albo ręcznie rysowanych lub powstała w wyniku działania
pewnej funkcji F (x0, x1, xn). Jak wynika z definicji najważniejszym kryterium
7 bryła widzenia - ogranicza tę część świata, która po rzutowaniu znajdzie się wewnątrz
okna widzenia
2.2 Definicja tekstury 7
podziału tekstur jest ilość posiadanych wymiarów. Najczęściej obecnie spotyka
się tekstury dwu i trzywymiarowe (rysunek 2 i 3).
Rysunek 2. Przykład obiektu obłożonego teksturą 2D
Rysunek 3. Różnica między teksturą 2D a 3D
Rysunek 4 przedstawia teksturę w nieznacznym powiększeniu. Poszczególne
piksele8 tekstury nazywamy tekselami (ang. texture element).
8 podstawowy, najmniejszy element obrazu
2.3 Proces nakładania tekstury 8
Rysunek 4. Przykład tekstury
2.3. Proces nakładania tekstury
Żeby nałożyć teksturę na wielokąt trzeba najpierw wyznaczyć współrzędne
tekstury na jego poszczególnych wierzchołkach (rysunek 10). Można to zrobić
jedną z podanych niżej metod mapowania9:
Mapowanie UV . Ta metoda mapuje teksturę dopasowując ją do obiektu tam,
gdzie zachodzi potrzeba rozciągając ją lub ściągając. Mapy tekstury zachowu-
ją swoją względną pozycję wobec obiektu, nawet kiedy obiekt zostaje skręcony
lub pofałdowany. To jedyna metoda nie wykorzystująca mapowania projekcyj-
nego polegającego na rzutowaniu obrazu na powierzchnię. Jest to najczęściej
spotykana metoda mapowania. Większość dostępnych pakietów 3D10 zawiera
specjalne narzędzia wspierające ten typ mapowania.
9 inaczej odwzorowanie10 Maya, 3D Studio MAX
2.3 Proces nakładania tekstury 9
Rysunek 5. Mapowanie UV
Mapowanie planarne . Ta metoda „przepycha” teksturę poprzez obiekt. Tek-
stura pojawia się na wszystkich ścianach obiektu, nawet wewnątrz i od tyłu.
Rysunek 6. Mapowanie planarne
Owinięcie względem poszczególnej osi dokonywane jest według następujących
wzorów:
x) u = Sz · z − cz, v = Sy · y − cy
y) u = Sx · x− cx, v = Sz · z − cz
z) u = Sx · x− cx, v = Sy · y − cy
gdzie Sx, Sy, Sz to współczynniki skalujące teksturę wzdłuż odpowiednich osi.
Można je wyznaczyć na zasadzie s=1/(rozmiar bryły w danej osi).
Mapowanie sferyczne . Jest to metoda, która owija sferycznie teksturę wokół
obiektu, powodując zbieganie się jej na górnym i dolnym biegunie.
2.3 Proces nakładania tekstury 10
Rysunek 7. Mapowanie sferyczne
Owinięcie sferyczne względem poszczególnej osi dokonywane jest według wzo-
rów:
x) u =Su2 · π· arc tg
(z
y
)− ou, v = Sv
π· arc tg
(x√
x2 + y2 + z2
)− ov
y) u =Su2 · π· arc tg
(x
z
)− ou, v = Sv
π· arc tg
(y√
x2 + y2 + z2
)− ov
z) u =Su2 · π· arc tg
(x
y
)− ou, v = Sv
π· arc tg
(z√
x2 + y2 + z2
)− ov
gdzie Su, Sv to współczynniki skalujące a ou, ov to współrzędne środka tek-
stury.
Mapowanie cylindryczne . Ta metoda powoduje owinięcie tekstury wokół obiek-
tu w cylindryczny sposób. Tekstura rozmazuje się do środka obiektu na jego
szczycie i dnie, jeśli jest dłuższa od obiektu (w górę lub w dół).
Rysunek 8. Mapowanie cylindryczne
Owinięcie względem poszczególnej osi dokonywane jest według wzorów:
x) u =Su2 · π· arc tg
(z
y
)− ou, v = Sv · x− ov
y) u =Su2 · π· arc tg
(x
z
)− ou, v = Sv · y − ov
z) u =Su2 · π· arc tg
(x
y
)− ou, v = Sv · z − ov
2.3 Proces nakładania tekstury 11
gdzie Su, Sv to współczynniki skalujące a ou, ov to współrzędne środka tek-
stury.
Mapowanie sześcienne (kubiczne) . Jest to metoda nakładania tekstury z
sześciu stron, nawet jeśli zaznaczony obiekt nie jest prostopadłościanem.
Rysunek 9. Mapowanie kubiczne
Rysunek 10. Przyporządkowanie współrzędnych tekstury odpowiednim wierzchołkom
Po wyznaczeniu odpowiednich współrzędnych tekstury można przystąpić do jej
nakładania na siatkę geometryczną. Na przykładzie trójkąta przedstawię najbar-
dziej rozpowszechniony11 algorytm teksturowania scan-line12. Algorytm ten pole-
ga na interpolacji współrzędnych tekstury przypisanych do odpowiednich wierz-
chołków trójkąta wzdłuż jego przeciwległych krawędzi i dla każdej pary takich
współrzędnych interpolacji wzdłuż linii łączącej te krawędzie. Dla każdej tak wy-
znaczonej współrzędnej zostaje pobrany odpowiedni teksel z mapy bitowej, który
następnie jest umieszczany na trójkącie. Oto co się dokładnie dzieje:
1. W pierwszym kroku sortuje się współrzędne trójkąta względem osi y, od naj-
wyżej położonego wierzchołka do położonego najniżej, wyznaczając przy oka-
zji najdłuższą krawędź trójkąta.
11 algorytm ten w wersji klasycznej jest też najwolniejszy12 skanowanie linia po linii
2.3 Proces nakładania tekstury 12
2. Następnie wyznacza się przyrosty na osi x i na osi u dla każdej krawędzi
trójkąta
dxn =xn+1 − xnyn+1 − yn
dun =un+1 − unyn+1 − yn
dvn =vn+1 − vnyn+1 − yn
3. gdzie n - numer kolejnej krawędzi < 0 . . . 2 > Wypełnianie trójkąta przebiega
według poniższego pseudokodu:
dxs = dx0 ; /∗ przyros ty na l ewe j krawędzi t r ó j k ą t a ∗/dus = du0 ;dvs = dv0 ;
dxe = dx1 ; /∗ przyros ty na prawej krawędzi t r ó j k ą t a ∗/due = du1 ;dve = dv1 ;
xs = xe = x0 ; /∗ nadanie war to ś c i początkowych ∗/us = ue = u0 ;vs = ve = v0 ;
/∗ dla każdej l i n i i z k t ó r e j składa s i ę t r ó j k ą t ∗/
f o r ( y = y0 ; y <=y2 ; y++){du = ( ue−us ) / ( xe−xs ) ; /∗ przy ro s t du na l i n i i ł ą c z ą c e j ∗/
/∗ p r z e c iw l e g ł e krawędzie t r ó j k ą t a ∗/dv = ( ve−vs ) / ( xe−xs ) ; /∗ przy ro s t dv na l i n i i ł ą c z ą c e j ∗/
/∗ p r z e c iw l e g ł e krawędzie t r ó j k ą t a ∗/u = us ;v = vs ;
f o r ( x = xs ; x <= xe ; x++){/∗ pobranie t e k s e l a z mapy b i towe j i wstawienie ∗//∗ go w odpowiednie mie j s c e na t r ó j k ą c i e ∗/
putp ixe l (x , y , RGB(u , v ) ) ;
u += du ;v += dv ;
}
/∗ sprawdzenie czy n i e na s t ąp i ł a zmiana krawędzi ∗//∗ po prawej s t r o n i e ∗/
i f ( y == v1 . y ){
dxe = dx2 ;due = du2 ;
2.3 Proces nakładania tekstury 13
dve = dv2 ;}
us += dus ; /∗ o b l i c z e n i e ko l e jnych war to śc i ∗/vs += dvs ; /∗ x , u i v po l ewe j s t r o n i e ∗/xs += dxs ;
xe += dxe ; /∗ o b l i c z e n i e ko l e jnych war to śc i ∗/ue += due ; /∗ x , u i v po prawej s t r o n i e ∗/ve += dve ;
}
Przedstawiony algorytm można dość znacznie przyspieszyć. Pierwszą rzeczą któ-
rą warto wiedzieć, jest taka, że delty cząstkowe na obszarze całego trójkąta są
stałe, co oznacza, że nie trzeba liczyć przyrostów dla tekstury po prawej stronie
trójkąta [3]. Jednak największy wpływ na prędkość wykonywania algorytmu ma
pętla wewnętrzna, która wypełnia pojedynczą linię trójkąta. W czasach kiedy
cała wizualizacja dokonywała się programowo prześcigano się w pomysłach na jej
optymalizację, obecnie nie ma to większego znaczenia, gdyż cały proces tekstu-
rowania wykonują procesory graficzne. (rysunek 11)
Rysunek 11. Schemat algorytmu nakładania tekstury
2.3 Proces nakładania tekstury 14
Przedstawiony algorytm ma jedną zasadniczą wadę. Nie uwzględnia przestrze-
ni w której leży trójkąt. Interpolacja dokonuje się jedynie w oparciu o zrzutowane
wartości 2D. Prowadzi to do dość znaczących błędów w obrazie, objawiający-
mi się zniekształceniami tekstur tym większymi im bardziej dany wielokąt jest
odchylony od rzutni w przestrzeni 3D (zniekształcenia nie występują kiedy wie-
lokąt jest równoległy do płaszczyzny rzutującej). Różnice między algorytmem z
i bez korekcji perspektywy przedstawia rysunek 12.Żeby podany powyżej algo-
rytm dokonywał korekcji perspektywy, każdą współrzędną (u, v) trójkąta i każdy
przyrost tekstury trzeba dodatkowo podzielić przez wartość współrzędnej z odpo-
wiedniego wierzchołka. Trzeba też interpolować wartości z dla każdej krawędzi.
Niestety, uwzględnienie korekcji perspektywy znacząco obniża wydajność algo-
rytmu, ze względu na fakt, że w pętli wypełniającej poszczególne linie trójkąta
dla każdego piksela trzeba dokonać dwóch dzieleń odpowiednio dla u i dla v (lub
dwóch mnożeń przez odwrotność dzielenia czyli 1zco jest nieznacznie szybsze).
Ponieważ dzielenie jest operacją pochłaniającą stosunkowo dużo czasu procesora,
radzono sobie w inny sposób. Dokonywano go tylko co pewną, ustaloną liczbę
pikseli (najczęściej 8 lub 16). Wartości pomiędzy dzieleniami były interpolowane.
Rezultatem była zadawalająca prędkość i nieznaczne uszczerbki na wyświetlanym
obrazie. Mimo różnych zabiegów optymalizacyjnych wydajność softwarowych al-
gorytmów pozostawia wiele do życzenia. O ile ich zadaniem jest tylko nakładanie
tekstur to radzą sobie nienajgorzej, to gdy zachodzi potrzeba dodania innych
efektów (oświetlenie, nakładanie dwóch tekstur jednocześnie) trzeba zwrócić się
ku rozwiązaniom sprzętowym.
Rysunek 12. Tekstura z (po lewej) i bez korekcji perspektywy
2.4 Rodzaje tekstur 15
2.4. Rodzaje tekstur
2.4.1. Tekstury rastrowe
Tekstura rastrowa to najczęściej prostokątna bitmapa typu RGBA13. Dzię-
ki temu może przedstawiać dowolny obraz. Mimo prostej organizacji i prostego
sposobu tworzenia (np.: poprzez skanowanie) tekstury rastrowe mają kilka istot-
nych wad: z góry ustalona rozdzielczość - tekstura o wymiarach 128x128
dobrze wygląda na ekranie tylko wtedy, kiedy wielokąt na który jest nałożona
po zrzutowaniu w pole widzenia zajmuje nieznacznie większą lub mniejszą po-
wierzchnię niż powierzchnia tekstury. Kiedy powierzchnia wielokąta przewyższa
znacznie powierzchnię tekstury (np.: kiedy zbliżamy się do ściany) powstaję nie-
pożądany efekt pikselizacji. Dzieje się tak ponieważ nie ma odwzorowania 1:1
piksela tekstury (teksela) do piksela wielokąta. Innymi słowy, na wiele pikseli
wielokąta przypada jeden teksel z mapy bitowej. Z kolei, kiedy zachodzi sytuacja
odwrotna, na jeden piksel przypada wiele tekseli, generowany obraz ulega defor-
macjom (tekstura traci szczegóły, niemożliwe staje się odczytanie niesionej przez
nią informacji). Aby zminimalizować ten efekt stosuje kilka różnych technik:
metoda najbliższego sąsiada - wybiera teksel leżący najbliżej środka stawia-
nego piksela. Niestety metoda ta powoduje duże zniekształcenia obrazu, po-
nieważ wybierany jest tylko jeden teksel z wielu mających wpływ na dany
piksel.
filtrowanie dwuliniowe - wybiera cztery sąsiadujące teksele i uśrednia je. Jest
to metoda niewiele lepsza od poprzedniej, dająca w wyniku lekko rozmazany
obraz (rysunek 13). Zawodzi, kiedy na jeden piksel ma wpływ więcej niż cztery
teksele.
13 każdy jej teksel składa się z czterech składowych koloru: czerwonego, zielonego, niebie-
skiego i kanału alfa
2.4 Rodzaje tekstur 16
Rysunek 13. Filtrowanie dwuliniowe
mip-mapping14 - dla określonej tekstury jest tworzonych kilka mniejszych, z
których każda następna stanowi 25% poprzedniej (wysokość i szerokość zmniej-
sza się o połowę). Ważnym jest, aby przy ich tworzeniu zastosować odpowied-
nie filtrowanie (najlepiej filtr Gaussa) i korekcję gamma, żeby uzyskać taki
sam kontrast jak tekstura wyjściowa. Metoda mip-mappingu polega na wy-
braniu takiej mimmapy, której powierzchnia jest najbliższa powierzchni ren-
derowanego wielokąta (zachodzi wtedy odwzorowanie powierzchni piksela do
teksela w stosunku 1:1 lub przynajmniej (2:1) (reguła Nyquist’a15)). W tym
celu wyznacza się tzw. współczynnik d (rysunek 14). Można go wyznaczyć
kilkoma sposobami. Jeden z nich polega na użyciu dłuższej krawędzi czworo-
boku utworzonego przez odwzorowanie powierzchni piksela na powierzchnię
nakładanej tekstury w celu aproksymacji stopnia jego pokrycia. Drugim jest
użycie największej bezwzględnej wartości z czterech różniczek:
∂u
∂x,∂v
∂x,∂u
∂y,∂v
∂y
Każda różniczka określa o ile współrzędne tekstury zmieniły się w stosunku do
osi ekranu. Na przykład ∂u∂xjest miarą zmiany wartości współrzędnej u wzdłuż
osi ekranu x dla jednego piksela.
15 Reguła Nyquist’a mówi, że częstotliwość samplowania musi być conajmniej dwukrotno-
ścią częstotliowści samplowanej próbki
2.4 Rodzaje tekstur 17
Rysunek 14. Mip-mapping
Rysunek 15. Efekt działania algorytmu mip-mappingu (po lewej - brak mip-mappingu)
filtrowanie trzyliniowe - jest to połączenie mip-mappingu i filtrowania dwuli-
niowego. Na podstawie współczynnika d wybiera się dwie mipmapy, z których
następuje pobranie i uśrednienie czterech sąsiadująych tekseli. Tak powstałe
wartości są liniowo interpolowane w zależności od odległości każdej mipmapy
do współczynnika d (który w tym przypadku nie jest wartością całkowitą, lecz
ułamkową, określającą odległoś pomiędzy odpowiednimi poziomami piramidy
mipmap).
Rysunek 16. Filtrowanie trzyliniowe
rip-mapping - metoda podobna do mip-mappingu, z tą różnicą, że tworzone
są także mapy zmieniające tylko wysokość lub tylko szerokość w stosunku
2.4 Rodzaje tekstur 18
do mapy wyjściowej (rysunek 17). W celu odczytania odpowiedniego teksela
koordynaty tekstury składają się z czterech współrzędnych: (u,v) - do okre-
ślenia odpowiedniego teksela danej podtekstury i dodatkowych dwóch (s,t) do
lokalizacji odpowiedniej podtekstury.
Rysunek 17. Rip-mapping
tablice sumacyjne - metoda tworząca tablicę o rozmiarze tekstury, ale prze-
znaczającą większą liczbę bitów na przechowywanie wartości kolorów (np.: 16
bitów na każdą poszczególną składową r,g,b). Następnie dla każdego elementu
tej tablicy należy obliczyć i zapamiętać sumę wszystkich tekseli wchodzących
w skład prostokąta, którego lewy, dolny róg znajduje się w punkcie (0,0) tabli-
cy, a prawy, górny w punkcie o współrzędnych odpowiadającym współrzędnym
tablicy aktualnie przetwarzanego elementu. W trakcie teksturowania określa-
ny jest prostokąt ograniczający projekcję obszaru piksela na obszar tekstury.
W celu ustalenia wartości koloru piksela uśrednia się wartości odczytane z
tablicy dla obszaru tego prostokąta za pomocą formuły:
c =s[xur, yur]− s[xur, yll]− s[xll, yur] + s[xll, yll])
(xur − xll)(yur − yll)
gdzie x i y są współrzędnymi teksela wyznaczonym przez prostokąt ogranicza-
jący, a s[x,y] wartością z tablicy sumacyjnej dla danego piksela.
filtrowanie anizotropowe - inne określenie dla technik rip-mappingu i tablic
sumacyjnych. Często łączy się je dla osiągnięcia lepszych rezultatów. Metody
filtrowania oparte na tych algorytmach mogą pobierać wartości tekseli, które
znajdują się na obszarach nie będącymi kwadratami. Rezultat działania takich
algorytmów przedstawia rysunek 18. Choć dają dobre wyniki, nie pozostają
bez wad, z których największą wydaje się być zapotrzebowanie na duże ilości
pamięci. Tablica sumacyjna dla tekstury o wymiarach 256x256 wymaga co
2.4 Rodzaje tekstur 19
najmniej dwukrotnie więcej pamięci niż sama tekstura, a ripmapy trzy razy
więcej.
Rysunek 18. Filtrowanie anizotropowe
duże wymogi odnośnie pamięci - Jeśli założyć, że na scenie znajduje się
20 różnych obiektów, a na każdy obiekt przypadają dwie tekstury o wymiarach
256x256 pikseli, gdzie piksel zajmuje 4 bajty (po 8 bitów na każdą składową koloru
r,g,b,a) - to okaże się, że potrzeba 10 megabajtów pamięci na zapamiętanie samych
tylko tekstur. To dużo - jeśli brać pod uwagę fakt, że bardzo często w systemach
czasu rzeczywistego przechodzi się z jednej sceny do drugiej i przejście to musi
być płynne. Jeżeli procesor graficzny nie dysponuje odpowiednią ilością pamięci
dla wszystkich scen będzie musiał je doczytać z pamięci masowej, co przeważnie
objawia się zacięciami w generowanej animacji. Trzeba dodatkowo zauważyć, że
przeważnie stosuje się mip-mapping, co w naszym przykładzie zakładając 3 pozio-
mowy mip-mapping zapotrzebowanie na pamięć zwiększy się do 13 megabajtów.
Z „apetytem” na pamięć próbuje się walczyć wprowadzając liczne rodzaje algo-
rytmów kompresujących. Procesor graficzny trzyma w pamięci skompresowaną
postać tekstury i w czasie rasteryzacji dynamicznie ją rozkodowuje i sięga po
odpowiedni teksel. Jak pokazuje rzeczywistość pomimo wyposażania procesorów
graficznych w mechanizmy kompresji danych, stale rośnie ilość pamięci, którą one
dysponują. Jeszcze nie tak dawno standardem było 32 Mb. Obecnie instaluje się
już nawet 256 Mb.
większe zapotrzebowanie na przepustowość pamięci - rysunek 19 po-
kazuje jak wiele wymaga się od magistrali pamięci procesora graficznego. Najbar-
dziej wymagające pod tym względem są:
— Bufor ramki przechowywany w pamięci lokalnej, który składa się z frontowe-
go i tylnego, a w przypadku potrójnego buforowania nawet z trzeciego bufora.
Te bufory mają rozmiar dokładnie odpowiadający rozdzielczości ekranu po-
2.4 Rodzaje tekstur 20
mnożonej przez głębię koloru. Jednostka renderująca korzysta z bufora ramki
kilka razy na każdy piksel.
— Bufor Z jest również tak samo duży, jak rozdzielczość ekranu razy głębia
bufora Z. Bufor Z kładzie wielki nacisk na przepustowość pamięci, ponieważ
jest najczęściej używaną częścią pamięci graficznej (odwołanie do bufora Z
następuje w zawsze kiedy stawiany jest nowy piksel).
— Bufor tekstur, który przechowuje skompresowane, bądź nie, tekstury, do
których dostęp jest szybszy w pamięci lokalnej, aniżeli gdyby jednostka ren-
derująca musiała ściągać je z pamięci systemowej przez szynę AGP. Znowu,
tekstury muszą być odczytane kilka razy na każdy piksel, w zależności od opcji
filtrowania i ilości tekstur nakładanych na piksel.
— Na końcu, ale nie mniej ważny jestRAMDAC, który musi odczytać frontowy
bufor ramki, by wyświetlić go na ekranie. Im wyższa rozdzielczość i im wyższa
częstotliwość odświeżania, tym częściej RAMDAC musi mieć dostęp do bufora
ramki.
Jak widać bufor tekstur ma dość istotny wpływ na przepustowość pamięci, co z
kolei przekłada się na płynność wyświetlanej animacji.
Rysunek 19. Obciążenie pamięci lokalnej procesora graficznego
2.4 Rodzaje tekstur 21
2.4.2. Tekstury proceduralne
Tekstura proceduralna jest to tekstura, która powstaje wskutek działania
funkcji F (). Funkcja ta przeważnie ma następującą postać:
kolor = F (x, y, z, . . .)
gdzie x,y,z to współrzędne punktu, dla którego jest generowana tekstura, a kropki
oznaczają dodatkowe parametry sterujące funkcją lub wpływające na jej działa-
nie. Ciało funkcji to zbiór dowolnych instrukcji danego języka programowania,
które w wyniku swojego działania zwracają kolor dla aktualnie wyświetlanego
punktu. Z punktu widzenia momentu użycia funkcji F () można wyróżnić dwa
typy tekstur proceduralnych:
1. generowane statycznie - funkcja F () służy do wygenerowania tekstury
przed uruchomieniem systemu generującego grafikę 3D (ang. engine). Tak
wygenerowana tekstura jest używana jako tekstura rastrowa.
2. generowane dynamicznie - funkcja F () wołana jest w trakcie działania
programu generującego obraz 3D każdorazowo w momencie stawiania piksela
w buforze ramki na etapie rasteryzacji wielokąta.
Podejście pierwsze, choć nie eliminuje wad tekstur rastrowych16 ma jedną,
niezaprzeczalną zaletę. Pozwala znacznie ograniczyć rozmiar programu17 (zakła-
dając, że większość tekstur jest generowana w taki właśnie sposób). Po drugie,
można zawsze, gdy zaistnieje taka potrzeba wygenerować te same tekstury, ale
w większej rozdzielczości. Jest to bardzo ważna zaleta, zwłaszcza teraz, kiedy
użytkownicy komputerów dysponują kartami graficznymi o zróżnicowanej mocy
i możliwościach. Ktoś, kto posiada mocną jednostkę komputerową może sobie
zażyczyć tekstur o wysokiej rozdzielczości, ktoś inny wręcz odwrotnie. Do tej
pory należało dołączyć do programu dla każdej tekstury kilka jej wersji dla każ-
dej uwzględnionej przez producenta oprogramowania rozdzielczości. Poszerzało to
znacznie rozmiary danego programu. Po trzecie może się okazać że wygenerowanie
przykładowo stu tekstur o rozmiarach 512x512 jest szybsze niż odczytanie ich z
pamięci masowej (zwłaszcza CD-ROM’u). Skraca się wtedy czas oczekiwania na
„załadowanie następnej planszy w grze”.
Podejście drugie nie dość że uwalnia od wcześniej wymienionych wad i ograni-
czeń tekstur rastrowych, to łączy zalety wymienione w punkcie poprzednim. Znika
16 patrz rozdział poprzedni - „Tekstury rastrowe”17 rozmiar programu - program wykonywalny razem z danymi potrzebnymi do jego dzia-
łania
2.4 Rodzaje tekstur 22
więc zapotrzebowanie na duże ilości pamięci i wysoką jej przepustowość18, a w
stosunku do tekstur proceduralnych generowanych statycznie znika problem skoń-
czonej rozdzielczości (inaczej mówiąc dokładności, widocznych detali) tekstury.
Teraz nie ma już tekstury o z góry określonych rozmiarach. Rozważmy wcześniej
już użyty przykład zbliżania się do ściany. Przy tradycyjnym podejściu, kiedy
gracz podchodził bliżej ściany, widział coraz więcej jej detali (zakładając, że ścia-
na składa się z chropowatych cegieł), ale tylko do momentu kiedy powierzchnia
tekstury nie przekraczała powierzchni renderowanego wielokąta. Potem widział
już tylko coraz większe piksele (rysunek 20). Używając prostej funkcji generującej
takie cegiełki problem całkowicie znika, ponieważ rozdzielczość staje się nieskoń-
czona (oczywiście jeśli odpowiednio napisze się taką procedurę, np.: można do
niej przekazywać odległość obserwatora (gracza) od ściany i w zależności od jej
wartości generować odpowiednio cegiełki).
Rysunek 20. Powiększanie tekstury proceduralnej i rastrowej
Pomimo niezaprzeczalnych zalet tekstur proceduralnych, nie da się nimi zastąpić
tekstur rastrowych ze względu na dwie największe ich wady:
1. brak możliwości uzyskania dowolnego obrazu. Nie da się na przykład (lub jest
to bardzo skomplikowane) wygenerować ludzkiej twarzy (skórę jak najbar-
dziej, ale nie takie elementy, jak oczy czy nos)
2. czasochłonność. Skomplikowane wzory (lub te nawet pozornie proste) mogą
wymagać użycia zaawansowanej matematyki o dużej złożoności obliczeniowej,
co uniemożliwia ich użycie w czasie rzeczywistym.
18 tylko odnośnie tekstur
2.4 Rodzaje tekstur 23
2.4.3. Przykłady tekstur proceduralnych
Tekstury proceduralne idealnie nadają się do odwzorowywania wszelkiego ro-
dzaju wzorów, powierzchni czy materiałów charakteryzujących się pewną regular-
nością. Inaczej mówiąc takich, których dowolnie wybrane fragmenty są do siebie
podobne. Takim materiałem jest np.: szachownica (krata) albo marmur. Poniżej
przedstawię kilka przykładów tekstur proceduralnych wraz z programami je ge-
nerującymi:
Okręgi
ko lo r Okręgi (x , y , pa l e ta ){
a = x − 0.5b = y − 0.5c = sq r t ( a ∗ a + b ∗ b)re turn pa l e ta [ c ∗ 2 5 6 ]
}
gdzie x, y - współrzędne stawianego piksela < 0 . . . 1 >
paleta - 256 elementowa tablica kolorów
Rysunek 21. Wynik działania funkcji Okręgi
Cegły
ko lo r Cegła (x , y , wysokość , s ze rokość , odstęp ){
p r z e s un i ę c i e = sz e roko ś ć / 2 . 0 ;
s t a t i c k = 0 . 0 ;
i f ( k == 0.0)p r z e s un i ę c i e = 0 .0
e l s e
2.4 Rodzaje tekstur 24
p r z e s un i ę c i e = sz e roko ś ć / 2 . 0
xp = (x + p r z e s un i ę c i e ) mod ( s z e roko ś ć + odstęp )yp = y mod ( wysokość + odstęp )
i f ( xp < odstęp | | yp < odstęp )re turn k o l o r b i a ł y
e l s ere turn ko lor czerwony
i f ( yp == 0.0 && x == 1.0)k = 1 − k
}
Rysunek 22. Wynik działania funkcji Cegła
Dużo lepsze efekty można osiągnąć stosując funkcję szumu, która jest bardzo
powszechnie stosowana w celu nadania generowanym teksturom pozorów natu-
ralności. Najczęściej stosowanym typem takiej funkcji jest funkcja opracowana
w 1985 roku przez Ken’a Pelin’a [5]. Podstawowym założeniem tej funkcji jest
utworzenie ciągu liczb losowych i interpolowanie jego wartości dla elementów
pośrednich. Dodatkowo sumuje się szumy o różnej częstotliwości i amplitudzie.
Liczbę sumowanych map szumu określa się jako oktawy. W celu uzyskania róż-
nych efektów końcowych stosuje się również przekształcenia uzyskanej wartości
szumu, a dla wartości wejściowych funkcji stosuje się skalowanie (co odpowiada
przybliżaniu, oddalaniu się od generowanej tekstury). Dla danej tekstury została
wygenerowana odpowiednia paleta barw (256 elementowa tablica kolorów RGB,
na odpowiedni indeks w tej tablicy wskazuje N(x)∗256, gdzie N(x) oznacza war-tość końcową funkcji szumu). Dla uzyskanych wyników podaję wartości freqMod
(modulator częstotliwości dla kolejnej mapy) i amplMod (modulator amplitudy
dla kolejnej mapy) oraz liczbę oktaw. Przy pomocy programu „Noise Generator”
[8] uzyskałem następujące tekstury.
2.4 Rodzaje tekstur 25
Modulator częstotliwości: 2.0
Modulator amplitudy: 0.65
Liczba oktaw: 5
Skala: 200
Wartość końcowa: N(x) =√N(x)
Rysunek 23. Marmur
Modulator częstotliwości: 2.0
Modulator amplitudy: 0.55
Liczba oktaw: 4
Skala: 510
Wartość końcowa:
N(x) = N(x) ∗ 10−Round(N(x))
Rysunek 24. Drzewo
Modulator częstotliwości: 2.0
Modulator amplitudy: 0.65
Liczba oktaw: 5
Skala: 35
Rysunek 25. Korona drzewa
2.4 Rodzaje tekstur 26
Modulator częstotliwości: 2.0
Modulator amplitudy: 0.75
Liczba oktaw: 3
Skala: 200
Wartość końcowa: N(x) =√N(x)
Rysunek 26. Rozbłyski
2.5 Sprzętowa realizacja procesu teksturowania 27
2.5. Sprzętowa realizacja procesu teksturowania
2.5.1. Architektura współczesnych kart graficznych
Za proces teksturowania w akcelatorach graficznych odpowiedzialne są jed-
nostki teksturujące (ang. texture units) organizowane w potoki. W zależności od
modelu karty różna jest ich ilość i właściwości. Obecnie najczęściej spotykane
konfiguracje to 4 potoki zawierające po 2 jednostki teksturujące lub 8 potoków
zawierających po 1 jednostce teksturującej. Organizacja potokowa umożliwia ra-
steryzację kilku pikseli wielokąta na raz. Im więcej potoków tym szybciej restery-
zowany jest wielokąt. Jeżeli na dany potok przypada więcej niż jedna jednostka
teksturująca procesor graficzny może w 1 cyklu nałożyć n-tekstur na dany piksel
(n-ilość jednostek). W pierwszym przypadku mówi się o szybkości wypełniania
pikseli (ang. pixel fillrate) ,w drugim o szybkości wypełniania tekseli (ang. texel fil-
lrate). Mając do wypełnienia określoną scenę, na której każdy obiekt pokryty jest
dwiema teksturami, karta o architekturze 8x1 wykona to zadanie w tym samym
czasie co karta zbudowana w architekturze 4x2 (zakładają zgodność wszystkich
innych parametrów karty tj. częstotliwość układu, przepustowość pamięci itd.).
Pierwsza karta wykorzysta dwa potoki (każdy dla jednej tekstury) na dany piksel,
karta druga zaś nałoży w każdym potoku dwie tekstury od razu. W każdym przy-
padku wypełnianie odbywa się dla 4 pikseli naraz. Jeżeli jednak na każdy obiekty
tej sceny przypadałaby tylko jedna tekstura, to karta pierwsza wykona to zadanie
2 razy szybciej. Widać więc przewagę organizacji 8x1. Ideałem byłaby organizacja
8x2, wiąże się to jednak z ilością użytych tranzystorów, co ma znaczący wpływ
na stopień skomplikowania konstrukcji, ilość wytwarzanego ciepła, a także cenę
końcową układu. Zanim nastąpi proces wypełniania wielokąta w pierwszym eta-
pie procesor geometrii przetwarza dane sceny 3D (rotacja, obcinanie, rzutowanie,
oświetlenie) i przekazuje je do jednostki rasteryzującej (ang. triangle setup raste-
rizer), która wyznacza metodą interpolacji współrzędne poszczególnych krawę-
dzi i wszystkie inne wartości przypisane wierzchołkom aktualnie przetwarzanego
wielokąta. Wszystkie te dane przekazywane są następnie do jednostki teksturu-
jącej, której zadaniem jest wyznaczenie na podstawie odpowiedniego algorytmu
(przeważnie scan-line przedstawiony w rozdziale poprzednim) albo koloru, albo
odpowiedniej wartości z tekstury dla każdego piksela wchodzącego w skład po-
szczególnych linii rasteryzowanego wielokąta. Zadaniem jednostki teksturującej
jest również dokonywanie korekcji perspektywy i filtrowania (dwu/trój-liniowego,
anizotropowego). W obecnie produkowanych układach jednostki teksturujące są
elementami programowalnych jednostek rasteryzujących (pixel shader). Przykła-
2.5 Sprzętowa realizacja procesu teksturowania 28
dy organizacji wiodących obecnie akcelatorów graficznych przedstawiają rysunki
27 i 28.
Rysunek 27. Schemat karty ATI Radeon 9700
Rysunek 28. Schemat karty geForce 5800
2.5 Sprzętowa realizacja procesu teksturowania 29
2.5.2. Pixel i Vertex Shader
Pierwsze akcelatory grafiki 3D wspomagały jedynie ostatni etap ścieżki prze-
twarzania - rasteryzację wielokątów (S3 Virge, 3DFX Voodoo). Kolejne generacje
tylko usprawniały ten proces (Riva TNT, Voodoo2) dokładając więcej potoków
renderujących. Przełomem okazało się wprowadzenie układu firmy nVidia geFor-
ce 256, który oferował sprzętową jednostkę przetwarzania oświetlenia i geometrii.
Nadal jednak programista był „skazany” na używanie z góry przewidzianych funk-
cji graficznych oferowanych przez procesor karty graficznej. O ile mógł dokonać
sprzętowej rotacji lub translacji wierzchołków, nałożyć tekstury, ustalić rodzaj
światła (kolor, natężenie, rozproszenie), to nie był w stanie zmusić karty do do-
konywania innych (przeważnie specjalistycznych) operacji np.: wygięcia obiektu
na kształt sinusoidy, zmieniania koloru każdego punktu tekstury w zależności od
kąta padania światła itd. Kiedy jednak koncern nVidia wyprodukował pierwsze
karty geForce 3 sytuacja zmieniła się diametralnie. Użytkownik nie tylko otrzy-
mał układ realizujący wszystkie podstawowe funkcje grafiki 3D, ale otrzymał
także możliwość ingerowania we wnętrze potoku 3D. Stało się to możliwe dzięki
zastosowaniu w pełni programowalnych jednostek przetwarzania geometrii i ra-
steryzacji, które otrzymały nazwy - odpowiednio vertex i pixel shader19 (rysunek
29).
2.5.3. Zasada działania Vertex Shader’a
W tradycyjnym potoku przetwarzania20 często dochodziło do podziału pra-
cy między procesorem głównym a procesorem graficznym, a czasem nawet do
jej dublowania. Działo się tak dlatego, ponieważ karta graficzna nie wspierała
wszystkich przekształceń geometrii, które wymyślił twórca aplikacji. Programo-
walna jednostka przetwarzania geometrii daje programiście pełną swobodę w wy-
myślaniu nawet skomplikowanych efektów graficznych, które do tej pory z powodu
ograniczeń w funkcjonalności jednostki T&L, bądź zbyt słabej wydajności pro-
cesora głównego nie były możliwe do uzyskania. Dzięki jednostce vertex shader
możliwe są do uzyskania takie efekty jak np.:
— geometria proceduralna (symulacja ubrań (naturalne ruchy materiału nałożo-
nego na bryłę sztywną będącą w ruchu), bańki mydlane)
— zaawansowane przenikanie werteksów używane do morfingu
— generacja tekstur
19 jednostki cieniowania werteksów i pikseli20 tu - karty ze sprzętową jednostką T&L
2.5 Sprzętowa realizacja procesu teksturowania 30
Rysunek 29. Miejsce jednostek pixel i vertex shader’a w potoku graficznym
— zaawansowana interpolacja klatek kluczowych (złożone ruchy twarzy i wymo-
wa)
— system cząsteczek
— modyfikacja widoku perspektywy w czasie rzeczywistym (efekt soczewki, efekt
bycia pod wodą)
— zaawansowane oświetlenie modeli 3D (często używane razem z pixel sha-
der’em)
Rysunek 30 przedstawia wewnętrzną organizację vertex shader’a. Zasada jego
działania opiera się na przetwarzaniu na zasadzie kolejki tylko jednego wierzh-
chołka naraz. Oznacza to, że program vertex shadera wykonuje się dla każdego
wierzchołka sceny osobno. W momencie gdy zostaje uruchomiony program vertex
shader’a odłączona zostaje jednostka T&L. Na wejściu w rejestrach od v0 do v15
vertex shader dostaje wszystkie dane aktualnie przetwarzanego wierzchołka:
2.5 Sprzętowa realizacja procesu teksturowania 31
v0 pozycja wierzchołka
v1 waga mieszana
v2 indeksy mieszania
v3 normalna
v4 wielkość punktu
v5 kolor wierzchołka
v6 kolor odbicia
v7. . . v14 współrzędne kolejnych 8 tekstur
Rejestry od r0 do rN21 służą do zapisywania i odczytywania wartości tymcza-
sowych, np.: koloru tekstury. Rejestry od c0 do cN są rejestrami pamięci stałej
dla liczb zmiennoprzecinkowych, poprzez które można przekazywać parametry
programu, np.: rozwinięcia funkcji sinus. Analogiczne zastosowanie mają rejestry
i0. . . iN (dla wartości całkowitych) i b0. . . bN (dla wartości logicznych). Ostatni
rejestr a zwiera ofset (przesunięcie), które wskazuje na aktualnie czytany rejestr
pamięci stałej. Na wyjściu zwracane są przetworzone współrzędne wierzchołka,
jego kolor, a także wszystkie inne dane skojarzone z określonym wierzchołkiem,
a potrzebne w dalszej ścieżce przetwarzania. Każdy rejestr ma długość 128 bi-
tów, co wystarcza do przechowania czterech liczb zmiennoprzecinkowych (np.:
współrzędnych x,y,z,w wierzchołka). Program vertex shader’a to zbiór instrukcji
realizujących takie zadania jak iloczyn skalarny, mnożenie wektora przez macierz,
dodawanie itp. W zależności od wersji vertex shadera różna może być liczba in-
strukcji i różny stopień ich zaawansowania. Przykładowo wersja 1.3 przewiduje
liczbę instrukcji do 128, w wersji 2.0 już do 256. Poniższa tabelka przedstawia
zasadnicze różnice pomiędzy dostępnymi wersjami vertex shader’ów.
Wersja Vertex Shader’a 1.1 2.0 2.0+ 3.0
Liczba dopuszczalnych instrukcji 128 256 256 512+
Liczba rejestrów pamięci stałej 96 256 256 256
Liczba rejestrów tymczasowych 12 12 12 12
Liczba rejestrów wejścia 16 16 16 16
2.5.4. Zasada działania Pixel Shader’a
Zanim procesor graficzny postawi piksel na ekranie wykonuje program pixel
shadera (rysunek 31). Dzięki pixel shader’owi możliwe są do uzyskania efekty
takie jak:
21 liczba dostępnych rejestrów jest zależna od wersji shadera, wersja omawiana w tej pracy
ma numer 1.3
2.5 Sprzętowa realizacja procesu teksturowania 32
Rysunek 30. Wewnętrzna architektura vertex shader’a
— cienie,
— oświetlenie liczone dla pojedynczych pikseli,
— zaawansowane efekty przezroczystości,
— efekt mgły, wypukłości
Na wejściu pixel shader otrzymuje dane z jednostki przetwarzania geometrii T&L
albo z vertex shader’a. Tymi danymi są współrzędne punktu w przestrzeni na
który nakładana jest tekstura, jego kolor, współrzędne nakładanych tekstur, i
tak jak poprzednio specjalne parametry przekazywane poprzez rejestry pamięci
stałej. Specyficzny jest proces przetwarzania pojedynczego piksela. Jak widać to
na rysunku 32 pierwszym krokiem, jaki wykonuje pixel shader jest skopiowanie
danych wejściowych, po to aby móc bezpiecznie dokonywać operacji arytmetycz-
nych (operowanie na oryginalnych wartościach może doporwadzić do przekłama-
nych wyników). W kroku drugim następuje rozdzielenie koloru na dwie części:
na składowe r,g,b i kanał przezroczystości alfa. Teraz pixel shader wykonuje swój
program dla tych wartości (równolegle) i po zakończeniu uzyskany wynik przeka-
zuje do bufora ramki. Na wynik można nałożyć maskę, np. w celu nieuwzglęniania
składowej r przy tworzeniu ostatecznej wartości koloru, który zawsze jest zapi-
sywany w rejestrze r0. Ważną rzeczą w przypadku pixel shadera jest mechanizm
2.5 Sprzętowa realizacja procesu teksturowania 33
Rysunek 31. Wewnętrzna architektura pixel shader’a
adresowania tekstur (samplowanie, rysunek 33), czyli pobieranie odpowiednich
tekseli z tekstur. Samplowanie dokonuje się w oparciu o cztery informacje:
1. instrukcji adresowania użytej w pixel shaderze,
2. współrzędnych mapowania,
3. aktualnie ustawionej teksturze na danym poziomie tekstury (ang. stage),
4. różnych atrybutów obróbki tekstury ustawionych dla danego poziomu.
Rysunek 33 przedstawia drogę, jaką mogą przebyć współrzędne mapowania w
shaderach od wersji od 1.0 do 1.3, zanim zostaną użyte do uzyskania koloru
tekstury przypisanej danemu wielokątowi. Jak widać, dróg tych jest kilka a każda
z nich charakteryzuje się inną specyfiką:
kolor czerwony . W takim przypadku rejestry tekstury są ładowane bezpośred-
nio współrzędnymi mapowania a pixel shader posługując się nimi pobiera z
określonego miejsca na teksturze odpowiedni kolor bez żadnych dodatkowych
obliczeń.
2.5 Sprzętowa realizacja procesu teksturowania 34
Rysunek 32. Przetwarzanie pojedynczego piksela
kolor niebieski . Współrzędne mapowania są przekazywane do tzw. samplera
tekstury, który bazując na kilku wspomnianych wyżej typach danych pobie-
rze odpowiedni kolor z tekstury i umieści jego wartości w rejestrach tekstury.
Tekstura musi być ustawiona na jakimś konkretnym poziomie, z którego po-
bierane są dane o samplingu. Numer współrzędnych mapowania (wierzchołek
ma ich aż osiem par, podobnie jest z ilością dostępnych poziomów tekstur) za-
wsze koresponduje z numerem docelowego rejestru zastosowanego w instrukcji
shadera.
kolor żółty i zielony . Pewne instrukcje adresowe tekstur w konkretnych wer-
sjach pixel shadera przeprowadzają różne transformacje na wejściowych współ-
rzędnych teksturowania w celu utworzenia nowych współrzędne. Następnie
mogą one być użyte do samplowania tekstury (kolor zielony) lub być bezpo-
średnio przekazywane jako dane dla rejestrów tekstury (kolor żółty).
2.5 Sprzętowa realizacja procesu teksturowania 35
Rysunek 33. Mechanizm adresowania tekstur
Dla wersji pixel shadera 1.4 rejestry tekstur maja trochę inne znaczenie niż w
wersjach poprzednich. Zawierają one współrzędne tekstury więc widać niejako
podobieństwo do sposobu oznaczonego w poprzednich wersjach kolorem czerwo-
nym. Są to rejestry tylko do odczytu (używane jako rejestry wejściowe dla in-
strukcji adresowych) i nie można na nich przeprowadzać operacji arytmetycznych.
Fakt, że posiadamy współrzędne tekstury w rejestrach oznacza tylko tyle, że teraz
zbiór współrzędnych mapowania i numer poziomu tekstury wcale nie musza się
zgadzać. Numer poziomu, z którego dokonywane jest samplowanie tekstury okre-
ślany jest przez docelowy numer rejestru, ale zbiór współrzędnych tekstury jest
określany przez nowy rejestr wejściowy tN. Blok z rysunku 33 nazwany „zmiana
współrzędnych” nie jest obecny w shaderze w wersji 1.4, ponieważ modyfika-
cja współrzędnych tekstury przed samplowaniem tekstury jest osiągana w prosty
sposób przez użycie arytmetycznych instrukcji poprzedzonych tzw. zależnym od-
czytem, co oznacza, że dane tekstury, które dostaniemy w wyniku samplowania
będą zależeć od pewnych operacji, które dokonamy wcześniej. Dla wersji 1.0-1.3
shadera odczyt zależny także jest możliwy, ale jest bardzo ograniczony i spro-
wadza się tylko do zastosowania instrukcji adresowej używającej jako parametru
wejściowego rezultatu poprzednio zastosowanej instrukcji adresowej. Dla wersji
1.4 shadera odczyt zależny ma o wiele większe możliwości, ponieważ współrzęd-
ne mapowania mogą pochodzić nie tylko z poprzedniej instrukcji adresowej, ale
także z prawie dowolnej instrukcji arytmetycznej. Następne wersje pixel shader’a
ułatwiają programowanie jeszcze bardziej. Porównanie możliwości przedstawia
poniższa tabelka.
2.5 Sprzętowa realizacja procesu teksturowania 36
Wersja Pixel Shader’a 1.1 1.2 1.3 1.4 2.0 2.0+ 3.0
Liczba instrukcji 8 12 12 14 96 96-512 512-32768
Liczba rej. pamięci stałej 8 8 8 8 32 32 224
Liczba rej. tymczasowych 2 2 2 6 12 12 32
Liczba rej. tekstury 4 4 4 6 8 8 16
Liczba rej. koloru 2 2 2 2 2 2 2
37
3. Przegląd implementacji programów Pixel i Vertex
Shadera
3.1. Tekstury uzyskiwane metodą bump mappingu
Praca [17] używa pixel i vertex shader’a do uzyskania złudzenia wypukłości
powierzchni (bump-mapping). W przeciwieństwie do klasycznych metod używa-
jących tekstury o stałych rozmiarach, zawierającej informację o rozkładzie światła
na danym materiale, autorzy generują taką mapę w czasie rzeczywistym. Zapo-
biega to błędom w generowanej grafice , które miały miejsce przy użyciu innych
metod w momencie, kiedy odległość tekstury od obserwatora ulegała zmianie.
Wymaga jednak, aby powierzchnia bryły była materiałem określonym fraktalnie,
a model oświetlenia bazował na tzw. mikro-odcinkach (ang. microfacets).
Rysunek 34. Tekstura uzyskana metodą bump-mappingu
3.2. Tekstury powstałe w wyniku przekształceń afinicznych
Praca [19] pokazuje jak używać arytmetyki przekształceń afinicznych do ge-
nerowania tekstur proceduralnych. Autorzy używają języka shaderów Render-
Man’a, który można jednak łatwo przkszatłcić na język shaderów obecnych kart
graficznych (np.: Cg). Arytmetyka afiniczna (ang. affine aritchmetic) podobnie
jak arytmetyka przedziałów (ang. interval aritchmetic) gwarantuje określone za-
kresy (ang. bounds) dla uzyskiwanych wyników, biorąc pod uwagę reszty i błędy
zaokrągleń. Jendak w przeciwieństwie do arytmetyki przedziałów „śledzi” ścieżkę
korelacji pomiędzy wartościami powstałymi a wejściowymi, zapobiegając w ten
sposób dużym utratom dokładności w stosowanych obliczeniach.
3.3 Tekstury generowane za pomocą gotowych wzorów 38
Rysunek 35. Przykład tekstury uzyskanej za pomocą arytmetyki afinicznej
3.3. Tekstury generowane za pomocą gotowych wzorów
Metoda składania tekstury z kawałków innych, mniejszch tekstur o określo-
nych wzorach (grupowanych tematycznie, np.: powierzchna ziemi, każda z tekstur
zawiera inną jej część, jedna kępkę trawy, druga fragment gruntu, a trzecia kwia-
tek). Pozwala ona generować urozmaicone, niepowtarzające się wzory, przydatne
w odwzorowywaniu rozległych przestrzeni. W pracy [13] użytkownik komponuje
teksturę dla danej powierzchni z pewnych, wcześniej określonych wzorów, ustala
rozmiar wirtualnej siatki, określa dopuszczalne kombinacje wzorów i inne zależno-
ści rzutujące na wybór określonego wzoru charakterystyczne dla danego przypad-
ku (np.: odległość od punktu, czas). Następnie przestrzeń koordynatów tekstury
dla danej sceny jest dzielona na kształt tejże właśnie wirtualnej siatki. Zadaniem
pixel shader’a jest wybranie właściwej kratki siatki dla pary współrzędnych (u, v),
i określenie odpowiedniego wzoru na podstawie analizy parametrów zdefiniowa-
nych przez użytkownika.
Rysunek 36.
3.4 Tekstury „rysowane ołówkiem” 39
3.4. Tekstury „rysowane ołówkiem”
Metoda tworzenia tekstur sprawiających wrażenie rysowanych ołówkiem opie-
ra się na następującym schemacie. Dla danego obiektu jest generowany trójwy-
miarowy wzór T, który następnie dla każdego piksela jest porównywany z warto-
ścią natężenia światła tego obiektu I. Wynik porówniania decyduje, czy stawiany
piksel jest koloru białego, czy czarnego. W celu zmiękczenia przejścia pomiędzy
tymi dwoma kolorami wyznaczana jest różnica między T a I, którą mnoży się
przez pewien stały współczynnik c większy od 1. Praca [14] modyfikuje tą me-
todę łącząc kilka wzorów na jednej teksturze, przydzielając każdemu z nich inną
wartość odcienia szarości.
Rysunek 37. Przykład tekstury rysowanej ołówkiem
3.5. Tekstury generowane na podstawie fluktuacji światła
Program [12] używa programów pixel i vertex shader’a do utworzenia efektu
błyszczącej, oscylującej powierzchni oceanu złożonej z wielu poruszających się w
różnych kierunkach fal.
Programy vertex i pixel shader’a zostały użyte do implementacji odwzorowa-
nia kubicznej mapy otoczenia , deformacji siatki symulującej większe fale, a także
do implementacji dwóch map wypukłości symulujących fale mniejsze i indekso-
wanej mapy Fresnela dla uzyskania odpowiedniego koloru tafli wody.
Geometrię wejściową stanowi siatka czworokątów z jednym zbiorem koordy-
natów tekstury, normalnych i stycznych. Mapa otoczenia to prerenderowana tek-
stura słońca i chmur.
Vertex shader jest odpowiedzialny za generowanie kombinacji sinusoidalnych
fal zaburzających pozycję wierzchołków siatki i generowanie fal kosinusoidalnych
zaburzających przestrzeń wektorów stycznych do tych wierzchołków. Każda si-
nusoidalna fala posada w pełni sterowalny kierunek, częstotliwość, szybkość i
przesunięcie , które są zapamiętywane w rejestrach pamięci stałej vertex shader’a.
3.6 Tekstury oparte na funkcji szumu 40
Pixel shader jest odpowiedzialny za utworzenie wypukłej, odbijającej otocze-
nie powierzchni wody. Żeby osiągnąć pożądany efekt najpierw uśrednia wartości
z dwóch przesuwających się map wypukłości i na ich podstawie generuje wektor
normalny. Następnie przekształca przestrzeń wektorów normalnych do przestrzeni
świata i oblicza wektor odbicia dla każdego piksela. Wektor odbicia zostaje użyty
to pobrania odpowiedniego teksela z mapy środowiska. Program pixel shadera
oblicza także wektor odbicia zwierciadlanego 2 ∗ N · V i używa go do pobraniaodpowiedniego teksela z jednowymiarowej mapy Fresnela. Mapa Fresnela nadaje
wodzie bardziej zielonego wyglądu jeśli patrzeć na nią prosto z góry i bardziej
niebieskiego jeśli patrzeć na nią stojąc na brzegu.
W ostatniej fazie pixel shader składa kolor wody z wartości uzyskanych z
mapy Fresnela, z mapy otoczenia i z innych wartości odbić połyskowych również
uzyskanych z mapy otoczenia. Wartość pobraną z mapy otoczenia pierwiastkuje
się w celu uzyskania bardziej jaskrawych kolorów i zwiększenia kontrastu wody.
Żeby uzyskać światła połyskowe na wodzie, składowa połysku jest pobierana z
zielonej wartości składowej koloru mapy otoczenia. Ponieważ pożądanym efek-
tem są odbicia w wodzie odpowiadające jasnym punktom na niebie wartość tę
podnosi się do ósmej potęgi. Efektem końcowym jest ciemna woda, za wyjątkiem
najjaśniejszych obszarów mapy otoczenia, która się w niej odbija.
Rysunek 38. Wynik działania programu Ocean Water
3.6. Tekstury oparte na funkcji szumu
Szeroko stosowana funkcja opisywana również w tej pracy, używana do reali-
zacji zarówno statycznych jak i animowanych tekstur. Przy jej pomocy można
osiągnąć takie efekty jak: chmury [11], marmur czy drewno [16].
3.7 Tekstury fraktalne 41
Rysunek 39. Wynik działania programu [18]
3.7. Tekstury fraktalne
Program [10] za pomocą pixel shader’a oblicza wartości fraktala Manderbolta
wykonując dla każdego piksela 64 iteracje, co daje łączną liczbę 500 instrukcji.
Każda iteracja ma następującą postać:
ABSrt = AB ∗ AB;AB = (ABSrt . x − ABSrt . y − SC. x , 2 ∗ AB. x ∗ AB. y + SC. y ) ;i f ( ( ABSrt . x + ABSrt . x ) < Ki l lVa lue )
Color += ColorAdd ;
gdz i e :
Color = ( 0 , 0 , 0 , 0 ) ;
ColorAdd = ( 0 . 0 1 , 0 . 0 1 , 0 . 0 1 5 , 0 . 0 1 ) ;
AB = (0 , 0 ) ;
SC − współrzędne p i k s e l a
Rysunek 40. Wynik działania programu Manderbolt Fractal
3.8. Tekstury uzyskiwane drogą symulacji reakcji dyfuzji
Program [9] używa dyskretnego całkowania pary równań PDE (Partial Dif-
ferential Equations) znanej jako system reakcji dyfuzji Gray-Scott’a. System ten
reprezentuje wzajemnie koncentrujące się reakcje chemiczne. Poprzez wyświetla-
nie koncentracji w dwóch kanałach koloru można uzyskać zaskakujące wzory.
3.8 Tekstury uzyskiwane drogą symulacji reakcji dyfuzji 42
Użyty tu program dokonuje dyfuzji uśredniając sąsiadów poszczególnych pikseli
(skalowanych przez wartość współczynnika dyfuzji) i wyznacza wartość „reakcji”
oraz środkową część wyniku dyfuzji bazując na równaniach PDE, których postać
jest następująca:
∆(U)(x, y) = Du ∗ lap(U(x, y))− U(x, y) ∗ V (x, y)2 + F ∗ (1− U(x, y))
∆(V )(x, y) = Dv ∗ lap(V (x, y)) + U(x, y) ∗ V (x, y)2 − (F + k) ∗ V (x, y)
lap(f(x, y)) = f(x+ 1, y) + f(x− 1, y) + f(x, y + 1) + f(x, y − 1)
−4 ∗ f(x, y)
Vertex shader dokonuje wstępnych obliczeń potrzebnych do symulacji i renderin-
gu. Pixel shader wyznacza mapę wypukłości światła rozproszonego (ang. diffuse
light) tworząc mapy normalnych wynikających z koncentracji chemicznego „U”,
oraz dokonuje uśrednień wspomnianych wyżej.
Rysunek 41. Wynik działania programu Reaction Diffusion
43
4. Implementacja wybranych algorytmów teksturowania
Ponieważ pixel shader w wersji 1.0-1.4 ma dość ograniczone możliwości (pro-
blemy z adresowaniem, liczba dostępnych instrukcji), które okazują się niewystar-
czające przy sprzętowej realizacji tekstur proceduralnych, na potrzeby tej pracy
zostały użyte karty graficzne dysponujące pixel shader’em w wersji 2.0+, w któ-
rym oprócz zniesienia większości powyższych ograniczeń dodano wiele nowych
cech, takich jak np.: konstrukcje if, then, else, while, zwiększoną precyzję liczenia
koloru czy możliwość samplowania tekstury dowolną ilość razy w trakcie działa-
nia programu pixel shadera. Dodatkowo wykorzystany został kompilatora języka
pixel shader’a firmy nVidia „C for Graphics” (Cg) [15], który wspiera wszystkie
dostępne wersje i jest dodatkowo zgodny ze standardem OpenGL ARB22, który
obsługują zarówno karty firmy nVidia jak i ATI Technologies Inc. Użycie języ-
ka wyższego poziomu w znacznym stopniu ułatwia pisanie programów shadera i
dodatkowo uniezależnia od producenta danego procesora graficznego (mogą wy-
stępować różnice między shader’ami różnych producentów nawet dla tych samych
wersji).
4.1. Generator szumu Perlin’a
Funkcja szumu perlin’a służy do generowania spójnego (koherentnego) szumu
w przestrzeni. Pojęcie spójnego szumu oznacza, że dla dwóch dowolnych punktów
przestrzeni wartość funkcji szumu zmienia się „płynnie” w trakcie przesuwania się
od jednego punktu do drugiego. Inaczej mówiąc, nie występują nagłe skoki war-
tości pomiędzy punktami będącymi w bliskim sąsiedztwie (rysunek 42). Funkcja
szumu pobiera n współrzędnych z n-wymiarowej przestrzeni i dla tych współrzęd-
nych zwraca wartość z przedziału < −1 . . . 1 >. Przedstawiony poniżej algorytmgenerowania szumu perlin’a odnosi się do przestrzeni dwuwymiarowej, ale w pro-
sty (analogiczny) sposób można go rozszerzyć tak, aby działał w większej liczbie
wymiarów (korzyści z tego wynikające przedstawię na końcu tego rozdziału).
22 OpenGL ARB - Architecture Review Board, organizacja normalizująca standard
OpenGL (w jej skład wchodzi mn. 3D Labs, nVidia, ATI, Intel)
4.1 Generator szumu Perlin’a 44
Rysunek 42. Różnica między szumem zwykłym i koherentnym
W przestrzeni 2D funkcję szumu można zapisać jako:
szum2D(x, y) = z
gdzie x, y, z są wartościami rzeczywistymi. Funkcję szumu definiuje się w oparciu
o regularną siatkę, której punkty są określone dla liczb całkowitych. Każdy punkt
o współrzędnych rzeczywistych leży pomiędzy punktami tej siatki. Szukanie war-
tości funkcji szumu dla takich współrzędnych przebiega następująco: Najpierw
szuka się najbliżej położonych punktów siatki otaczających dany punkt. Dla prze-
strzeni 2D są to cztery punkty, odpowiednio (x0, y0), (x0, y1), (x1, y1) i (x1, y1)
(rysunek 43).
Rysunek 43. Cztery punkty siatki otaczające punkt (x, y)
Następnym krokiem jest zdefiniowanie funkcji
g(xg, yg) = (gx, gy)
4.1 Generator szumu Perlin’a 45
gdzie xg, yg to punkty siatki z przypisanymi pseudolosowymi23, znormalizowanymi
gradientami24 (rysunek 44).
Rysunek 44. Pseudolosowe gradienty przypisane punktom siatki
Dla każdego punktu siatki generowane są także wektory biegnące od danego
punktu siatki do punktu (x, y) (rysunek 45).
Rysunek 45. Wektory biegnące od punktów siatki do punktu dla którego generowana
jest wartość szumu
Mając określone gradienty oraz powyższe wektory, można obliczyć wartość
szumu dla punktu (x, y). Dokonuje się tego przez wyznaczenie wpływu gradien-
23 funkcja szumu dla każdego punktu siatki zawsze zwraca tę samą wartość niezależnie od
tego, ile razy jest wywoływana (w przeciwieństwie do klasycznej funkcji losowej, która zwraca
przy każdym wywołaniu różną wartość dla tego samego argumentu)24 w tym przypadku gradient oznacza uporządkowaną parę wektorów wskazujących na
określony punkt przestrzeni
4.1 Generator szumu Perlin’a 46
tów na wartość końcową funkcji i wyznaczeniu średniej ważonej tych wpływów.
Wpływ gradientów na wartość końcową oblicza się wyznaczając iloczyn skalarny
pomiędzy gradientami a odpowiednimi wektorami biegnącymi od punktów siatki
do punktu (x, y). Dla przestrzeni 2D powstaną cztery wartości:
s = g(x0, y0) · ((x, y)− (x0, y0))
t = g(x1, y0) · ((x, y)− (x1, y0))
u = g(x0, y1) · ((x, y)− (x0, y1))
v = g(x1, y1) · ((x, y)− (x1, y1))
Rysunek 46 przedstawia graficzną reprezentację obliczonych wartości wpływów.
Żeby wyliczyć końcową wartość funkcji można uśrednić s i t dla górnych narożni-
ków, u i v dla dolnych i tak powstałe wartości uśrednić raz jeszcze. Niestety tak
uzyskany szum nie wygląda zbyt „naturalnie”. Lepszą metodą jest interpolacja
wartości pomiędzy s i t oraz u i v za pomocą funkcji krzywej np.: c(p) = 3p2−2p3
(rysunek 47).
Rysunek 46. Graficzna reprezentacja wpływu gradientów punktów siatki
Rysunek 47. Wykres funkcji c(p) = 3p2 − 2p3
4.1 Generator szumu Perlin’a 47
Dzięki zastosowaniu takiej krzywej wartości wejściowe nie są uśredniane, ale
interpolowane wzdłuż łagodnego łuku dając w efekcie lepszy rezultat końcowy
(lepszą „jakość” szumu). Wartość końcową funkcji generuje się w następujący
sposób: Najpierw znajdywana jest wartość krzywej Sx(p) w punkcie p = x − x0(rysunek 48), którą odwzorowuje się z przedziału < 0 . . . 1 > na przedział <
s . . . t > (średnia a) i < u . . . v > (średnia b) używając interpolacji liniowej.
Obliczenia mają następującą postać:
Rysunek 48. Szukanie średnich a i b
Sx = 3(x− x0)2 − 2(x− x0)3
a = s+ Sx(t− s)
b = u+ Sx(v − u)
Kolejnym krokiem jest znalezienie wartość krzywej Sy(p) w punkcie p = y − y0,którą interpoluje się tak jak poprzednio za pomocą funkcji liniowej uzyskując
wartość z przedziału < a . . . b > będącej poszukiwaną wartością końcową (średnia
c). (rysunek 49).
Rysunek 49. Obliczanie wartości końcowej
4.1 Generator szumu Perlin’a 48
Sy = 3(y − y0)2 − 2(y − y0)3
c = a+ Sy(b− a)
Tak uzyskany szum charakteryzuje się mały stopniem zróżnicowania. Dlatego
końcowy szum uzyskuje się sumując szumy o różnej częstotliwości i amplitudzie
(rysunek 50) według poniższego równania:
N(x) =n∑i=1
szum(Frequencyi ∗ x)Ampitudei
Rysunek 50. Poszczególne składowe funkcji szumu [6]
gdzie n - liczba oktaw 25 przeważnie z zakresu < 1 . . . 10 >, ampl - maksy-
malna amplituda szumu, freq - częstotliwość szumu. Program korzysta z lekko
25 oktawa - funkcja szumu uzyskana dla określonej częstotliwości i amplitudy
4.1 Generator szumu Perlin’a 49
zmodyfikowanego wzoru na składanie szumu:
N(x) =n∑i=1
szum(Freqency ∗ x) ∗ Amplitude
Wartość początkowa freq i ampl wynosi 1. Wartości w kolejnych przejściach są
modyfikowane w sposób:
Freqency = Freqency ∗ FreqMod
Amplitude = Amplitude ∗ AmplMod
Program oblicza wartość szumu Perlin’a dla każdego punktu wyświetlanego
obiektu. Wartość ta wykorzystywana jest do obliczenia indeksu wskazującego na
odpowiedni kolor przechowywany w jednowymiarowej teksturze przechowującej
odpowiednio spreparowaną paletę kolorów. Kod programu wygląda następująco:
const f l o a t FreqMod = 2 . 0 ; /∗ modulator c z ę s t o t l i w o ś c i ∗/const f l o a t AmplMod = 0 . 65 ; /∗ modulator amplitudy ∗/const f l o a t TexWidth = 256 ; /∗ s z e roko ś ć t ek s tury szumu ∗/const f l o a t TexHeight = 256 ; /∗ wysokość t eks tury szumu ∗/const f l o a t TexDepth = 256 ; /∗ głębokość t eks tury szumu ∗/const f l o a t TexScale = 1 . 0 / 50 . 0 ; /∗ współ . ska lowania t eks tury ∗/const i n t Octaves = 4 ; /∗ l i c z b a oktaw ∗/
f l o a t Per l inNoise3D ( f l o a t x , f l o a t y , f l o a t z , sampler3D NoiseTex ){
i n t i x = ( i n t ) x ; /∗ wyznaczenie współrzędnych pierwszego ∗/i n t iy = ( i n t ) y ; /∗ lewego , górnego punktu s i a t k i szumu ∗/i n t i z = ( i n t ) z ;f l o a t dx = x − i x ; /∗ wyznaczenie współrzędnych punktu ∗/f l o a t dy = y − i y ; /∗ l e ż ą c ego pomiędzy punktami s i a t k i ∗/f l o a t dz = z − i z ; /∗ szumu ∗/
/∗ przeska lowan ie współrzędnych teks tury do ∗//∗ prz edz i a łu <0..1> ∗/
f l o a t tx0 = ( ix + 0 ) / TexWidth ;f l o a t tx1 = ( ix + 1 ) / TexWidth ;
f l o a t yknots [ 2 ] , zknots [ 2 ] ;
/∗ wyznaczenie war to ś c i szumu dla punktu ( dx , dy , dz ) na ∗//∗ za sadz i e i n t e r p o l a c j i l i n i ow e j war to ś c i szumu sąs iadu − ∗//∗ jących ze sobą punktów w każdym kolejnym wymiarze . ∗/
f o r ( i n t j = 0 ; j <= 1; j++){
f l o a t tz = ( i z + j ) / TexDepth ;
f o r ( i n t i = 0 ; i <= 1; i++){
f l o a t ty = ( iy + i ) / TexHeight ;
4.1 Generator szumu Perlin’a 50
/∗ pobranie war to ś c i szumu dla poszczegó lnych punktów ∗//∗ s i a t k i szumu ∗/
f l o a t a = tex3D (NoiseTex , f l o a t 3 ( tx0 , ty , tz ) ) . r ;f l o a t b = tex3D (NoiseTex , f l o a t 3 ( tx1 , ty , tz ) ) . r ;
yknots [ j ] = l e r p (a , b , dx ) ;}zknots [ k ] = l e rp ( yknots [ 0 ] , yknots [ 1 ] , dy ) ;
}
f l o a t r e s u l t = l e rp ( zknots [ 0 ] , zknots [ 1 ] , dz ) ;
r e turn clamp ( r e su l t , − 1 . 0 , 1 . 0 ) ;
}
f l o a t 4 main ( in f l o a t 3 TexCoord0 : TEXCOORD0,in f l o a t 2 TexCoord1 : TEXCOORD1,uniform f l o a t Depth ,uniform sampler3D Texture0 ,uniform sampler2D Texture1 ) : COLOR
{/∗ przeska lowan ie współ . t ek s tury ak tua ln i e rysowanego punktu ∗//∗ do prz edz i a łu <0. . .255> ∗/
f l o a t tx = TexCoord0 . x ∗ TexWidth ;f l o a t ty = TexCoord0 . y ∗ TexHeight ;f l o a t tz = TexCoord0 . z ∗ TexDepth ;
f l o a t Frequency = 1 . 0 ; /∗ i n i c j a l i z a c j a war to ś c i początkowych ∗/f l o a t Amplitude = 1 . 0 ;f l o a t Total = 0 .0 ;
f o r ( i n t i = 0 ; i < Octaves ; i++){
/∗ sumowanie powstałych zaburzeń ∗/
Total += Perl inNoise3D ( tx ∗ Frequency ∗ TexScale ,ty ∗ Frequency ∗ TexScale ,Depth ,Texture0 ) ∗ Amplitude ;
Frequency ∗= FreqMod ; /∗ zw iększan i e c z ę s t o t l i w o ś c i szumu ∗/Amplitude ∗= AmplMod ; /∗ zw iększan i e amplitudy ∗/
}
Total = Total ∗ 0 . 5 0 ;clamp ( Total , 0 . 0 , 1 . 0 ) ;
/∗ pobranie odpowiedniego ko loru z pa l e ty kolorów ∗/
return tex2D ( Texture1 , f l o a t 2 ( Total , 0 ) ) ;}
Do programu przekazywana jest tekstura 3D odpowiadająca siatce wartości
szumu z przedziału < −1 . . . 1 >. Ponieważ szum jest generowany dla przestrze-
4.1 Generator szumu Perlin’a 51
ni trójwymiarowej, a uzyskiwane wartości odwzorowywane są na powierzchnię
dwuwymiarowej tekstury, przekazywany jest dodatkowo parametr Depth zmie-
niający sie krokowo o nieduże wartości. Ta zmiana powoduje animację tekstury.
Po kompilacji program składał się z 316 instrukcji maszynowych. Wyniki działa-
nia programu przedstawia rysunek 51. Modyfikując wartość końcową i używając
odpowiednich amplidtud i częstotliwości oraz palety kolorów można uzyskać tek-
stury takie jak w rozdziale 2.4.2.
Rysunek 51. Rezultat działania programu Perlin Shader
4.2 Generator cząsteczek 52
4.2. Generator cząsteczek
Generowana tekstura to zbiór świecących cząsteczek lub plazma - w zależności
od użytej palety kolorów. Można jej użyć np. do uzyskania ciekawej powierzchni
planety (Jowisz - podrysunek 3 z rysunku 53), lub jako mapy odbić świateł np.
na kasku kosmonauty (wylosowane punkty muszą być wtedy zrzutowanymi na
powierzchnię tekstury pozycjami gwiazd w przestrzeni 3D). W pierwszej fazie pro-
gram losuje współrzędne dziesięciu punktów leżących na teksturze (rysunek 52).
Następnie dla każdego punktu generowanej tekstury oblicza odległość pomiędzy
tym punktem, a każdym punktem wylosowanym na początku. Suma odwrotności
tych odległości zastaje uśredniona i pomnożona przez eksperymentalnie dobra-
ny współczynnik (warunkujący różne efekty wizualne) dając w efekcie indeks w
palecie kolorów reprezentowanej przez jednowymiarową teksturę. W każdej ite-
racji ulegają zmianie wylosowane punkty tekstury w taki sposób, aby poruszały
się po elipsach o losowej długości promieni wyznaczonych na początku działania
programu. Dzięki zmianie pozycji wylosowanych punktów uzyskuje się animację
tekstury.
Rysunek 52. Algorytm generowania cząteczek
Listing programu pixel shader’a:
/∗ l i c z b a wyświetlanych c zą s t e c z ek ∗/
const i n t MaxPnt = 10 ;
/∗ współczynnik o d l e g ł o ś c i − im większy , tym mnie j sze ∗//∗ będą rysowane c z ą s t e c z k i ∗/
4.2 Generator cząsteczek 53
const f l o a t Factor = 10 . 0 ;
f l o a t p a r t i c l e ( f l o a t 2 vPos , f l o a t 2 vPnt [MaxPnt ] ){
f l o a t d i s t = 0 ;
f o r ( i n t i = 0 ; i < MaxPnt ; i++){
/∗ o b l i c z e n i e o d l e g ł o ś c i pomiędzy stawianym pikse lem ∗//∗ a i−tą c zą s t e c zką ∗/
f l o a t l en = d i s t anc e ( vPos , vPnt [ i ] ) ;
/∗ sumowanie odwrotnośc i o d l e g ł o ś c i od poszczegó lnych ∗//∗ c zą s t e c z ek ∗/
d i s t += 1.0 / l en ;}
/∗ ska lowanie o d l e g ł o ś c i ∗/
d i s t /= Factor ;
/∗ norma l i zac ja i negac ja o d l e g ł o ś c i ∗/
d i s t = 1 . 0 − ( 1 . 0 / dDist ) ;
r e turn d i s t ;}
f l o a t 4 main ( in f l o a t 2 TexCoord0 : TEXCOORD0,uniform f l o a t 2 vPoints [MaxPnt ] ,uniform sampler3D Texture0 ,uniform sampler2D Texture1 ) : COLOR
{
f l o a t t o t a l = p a r t i c l e ( f l o a t 2 (TexCoord0 . x , TexCoord0 . y ) , vPoints ) ;
/∗ ob c i ę c i e o d l e g ł o ś c i do pr z edz i a łu <0. . .1> ∗/clamp ( to ta l , 0 . 0 , 1 . 0 ) ;
/∗ pobranie ko loru z t eks tury z aw i e r a j ą c e j mapę kolorów ∗/return tex2D ( Texture1 , f l o a t 2 ( to ta l , 1 ) ) ;
}
Po kompilacji program składał się ze 105 instrukcji maszynowych. Wynik
działania programu przedstawia rysunek 53.
4.2 Generator cząsteczek 54
Rysunek 53. Rezultat działania programu Particles
4.3 Generator komórek 55
4.3. Generator komórek
Uzyskana tekstura to odzwierciedlenie systemu komórek żywej tkanki (np.:
roślinnej). Zdajdzie ona zastosowanie wszędzie tam, gdzie zachodzi potrzeba po-
kazania przekroju określonej tkanki. Można ją też stosować w futurystycznych
sceneriach, jako np.: powłoka wrot umożliwiających przejście do innego wymiaru.
Algorytm działania tego programu to wynik modyfikacji algorytmu programu po-
przedniego, która polega na szukaniu najmniejszej odległości pomiędzy generowa-
nym punktem tekstury a punktami wylosowanymi. Zmieniając pozycję punktów
kluczowych (odpowiadających pozycji jąder) można uzyskać efekt poruszających
się komórek, łączących się i rozdzielających. Algorytm można dodatkowo zmienić
tak, aby szukał kilku najmniejszych odległości (np.: 3). Sumę tych odległości trze-
ba wtedy uśrednić i znormalizować. Efektem będzie kilka warstw (liczba wartsw
odpowiada liczbie szukanych odległości) komórek poruszających się nad sobą.
Rysunek 54. Algorytm generowania komórek
Danymi wejściowymi do programu są współrzędne aktualnie stawianego tekse-
la, tekstura zawierająca paletę kolorów oraz tablica współrzędnych wylosowanych
wcześniej punktów. Dla każdego stawianego piksela wywoływana jest funkcja cell,
która zwraca wartość z przedziału < 0 . . . 1 >, na podstawie której jest odczyty-
wana wartość z tekstury zawierającej paletę kolorów.
/∗ l i c z b a wyświetlanych c zą s t e c z ek ∗/
const i n t MaxPnt = 10 ;
/∗ maksymalna od l e g ł o ś ć pomiędzy dwoma punktami ∗/
4.3 Generator komórek 56
/∗ na t ek s tu r z e o wymiarach 1/1 , c z y l i $ sq r t (2 ) $ ∗/
const f l o a t MaxDist = 1.4142
f l o a t c e l l ( f l o a t 2 vPos , f l o a t 2 vPnt [MaxPnt ] ){
f l o a t d i s t = 0 ;f l o a t minDist = 0 ;
f o r ( i n t i = 0 ; i < MaxPnt ; i++){
/∗ o b l i c z e n i e o d l e g ł o ś c i pomiędzy stawianym pikse lem ∗//∗ a i−tą c zą s t e c zką ∗/
f l o a t l en = d i s t anc e ( vPos , vPnt [ i ] ) ;
/∗ szukan ie na jmn i e j s z e j o d l e g ł o ś c i od c z ą s t e c z k i ∗//∗ dla aktualnego p i k s e l a ∗/
i f ( i == 0)minDist = len ;
e l s e i f ( l en < minDist )minDist = len ;
}
/∗ norma l i zac ja o d l e g ł o ś c i − przeska lowan ie do ∗//∗ prz edz i a łu <0. . .1> ∗/
d i s t = minDist / MaxPnt ;
re turn d i s t ;}
f l o a t 4 main ( in f l o a t 2 TexCoord0 : TEXCOORD0,in f l o a t 2 TexCoord1 : TEXCOORD1,uniform sampler2D Texture0 ,uniform sampler2D Texture1 ,uniform f l o a t 2 vPoints [MaxPnt ] ) ) : COLOR
{f l o a t t o t a l = c e l l ( f l o a t 2 (TexCoord0 . x , TexCoord0 . y ) , Points ) ;
/∗ pobranie ko loru z t eks tury z aw i e r a j ą c e j mapę kolorów ∗/
return tex2D ( Texture1 , f l o a t 2 ( to ta l , 1 ) ) ;}
Po kompilacji program składał się ze 123 instrukcji maszynowych. Wynik
działania programu przedstawia rysunek 55.
4.3 Generator komórek 57
Rysunek 55. Rezultat działania programu Cells
58
5. Analiza wydajnościowa procesu teksturowania
Celem tego rozdziału jest oszacowanie wydajności jednostek cieniujących obec-
nych akcelelatorów grafiki 3D. W tym przypadku oszacowanie wydajność oznacza
znalezienie granicznej ilości wielokątów, przy której liczba wyświetlanych klatek
obrazu na sekundę (ang. fps - frame per second) nie spada poniżej wartości za-
pewniającą płynną animację (25-30 fps). Ocenie była poddawana także jakość
generowanego obrazu.
5.1. Środowisko i procedura testowa
Testy zostały wykonane na komputerze klasy PC o następujących parame-
trach: procesor Athlon XP 2600+, pamięć 512 MB RAM, karta graficzna ATI
Radeon 9700. Każdy test wykonywał się przez 30 sekund, po czym liczona była
średnia liczba wyświetlanych klatek w ciągu sekundy (FPS - frame per second).
Testy były przeprowadzane w rozdzielczości 1024x768 o 32 bitowej palecie kolo-
rów.
Za teksturowany obiekt posłużyła siatka czworokątów o stałej zajętości po-
wierzchni obrazu, ale o zmieniającej się liczbie wielokątów w osi x i y (rysunek
56). Takie podejście pozwoliło określić, czy przy tej samej ilości renderowanych
pikseli liczba wierzchołków przypadająca na tą powierzchnię ma wpływ na pręd-
kość generowania obrazu (im więcej wierzchołków , tym więcej pracy wykonuje
triangle setup rasterizer). Żeby określić maksymalną liczbę wielokątów przy jakiej
zachowana jest płynność animacji, każdy rodzaj użytej siatki powielano n-razy w
osi z.
Ważnym elementem przy ocenie wydajności układów cyfrowych wyposażo-
nych w programowalne jednostki cieniujące jest stopień skomplikowania wykony-
wanych programów, na który się składają:
— liczba użytych instrukcji
— rodzaje instrukcji (czy są to instrukcje proste, takie jak: przeniesienie, doda-
wanie, czy złożone: dzielenie, pierwiastkowanie)
— ilość odwołań do pamięci tekstur (należy tu też zwrócić uwagę na odczyty
zależne (sytuacja kiedy koordynaty tekstury wykorzystywane do odczytu da-
nego teksela nie są wartościami bezpośrednio wyliczonymi przez procesor dla
danego piksela, ale modyfikacjami tych wartości lub kiedy wartość teksela
danej tekstury jest koordynatem dla innej tekstury odczytywanej w danym
przebiegu))
5.2 Wyniki testów 59
Użyte szadery w pełni wykorzystują zasoby pixel shader’a w wersji 2.0 jeśli
chodzi o liczbę i rodzaje instrukcji. Program „Perlin Noise 3D” po kompilacji
składał się z 317 instrukcji, z czego 51 dokonywało mnożenia, 87 dodawania, 32
liczyło odwrotności, a 33 dokonywało odczytów tekstury 3D. Szader „Cells” miał
89 instrukcji (dla 6 komórek), których rozkład wyglądał następująco - 33 prze-
niesienia, 12 dodawań, 6 odwrotności, 6 pierwiastków kwadratowych, 6 iloczynów
skalarnych, 6 porównań (instrukcje warunkowe) i 1 odczyt wartości z tekstury.
Szader „Particles” po kompilacji składał się (dla 6 cząsteczek) z 66 instrukcji,
gdzie 6 dokonywało mnożeń, 20 przeniesień, 13 liczyło odwrotności, 6 wykonywało
pierwiastkowanie i wyznaczało iloczyny skalarne, a 1 odczytu tekstury.
Testy nie zostały przeprowadzone dla szadera „Perlin Noise 3D” z powodu
braku dostępu do karty geForce FX, która dysponuje rozszerzoną w stosunku do
standardu jednostką pixel shader w wersji 2.0 ex, dopuszczającą wykonywanie
znacznie większej liczby instrukcji i nie ograniczającej ilości możliwych odczy-
tów tekstury (ps 2.0 - 24 odczyty). Programy „Particles” i „Cells” wykonywały
się tylko dla sześciu cząsteczek. Dla dziesięciu, programy wynikowe przekraczały
dopuszczalną liczbę instrukcji programu (ponad 100, dopuszczalne 96).
5.2. Wyniki testów
Testy zostały przeprowadzone dla następujących siatek czworokątków:
1. 5x5xX (5 czworokątów w osi x, 5 w y)
2. 10x10xX (100xN czworokątów (200xN trójkątów))
3. 30x30xX (900xN czworokątów)
4. 50x50xX (2500xN czworokątów)
gdzie parametr N przyjmował wartości 1,5,15,25.
Rysunek 56. Przykład siatki 5x5x1 i 50x50x1. Ta sama zajmowana powierzchnia, różna
liczba wierzchołków
5.2 Wyniki testów 60
Oto wyniki jakie uzyskano:
Rysunek 57. Rezultaty dla programu „Particles”
Rysunek 58. Rezultaty dla programu „Cells”
Uzyskane wyniki prowadzą do następujących wniosków:
1. Ilość użytych wielokątów ma niewielki wpływ na samą szybkość wypełniania
pikseli. Pomimo znaczącego „zagęszczania” siatki wielokątów szybkość wy-
pełniania dla tej samej powierzchni pozostawała mniej więcej na tym samym
poziomie. Największy spadek wydajności (w przypadku obu testowanych sza-
derów) - o 10 klatek na sekundę - wystąpił pomiędzy sceną złożoną z 9000
trójkątów (siatka 30x30x5) a sceną złożoną z 1000 trójkątów (siatka 10x10x5).
Jest to 20 procentowy spadek wydajności w stosunku do 900 procentowego
wzrostu złożoności sceny, a więc stosunkowo nieduży.
5.2 Wyniki testów 61
2. Maksymalna liczba wielokątów (trójkątów), przy której prędkość animacji nie
spada poniżej dopuszczalnej wartości jest trudna do oszacowania. Z wykresów
wynika ,że wydajność procesora graficznego przy użyciu programów cieniu-
jących jest ograniczana szybkością wypełniania pikseli (ang. pixel fillrate).
Np.: dla siatki 5x5x15 (750 trójkątów) ilość klatek na sekundę (10,2) jest
prawie taka sama jak dla siatki 30x30x15 (13500 trójkątów), która wynosi 8,1
fps. Żeby zatem określić maksymalną liczbę trójkątów, trzeba najpierw okre-
ślić maksymalną szybkość wypełniania (która z kolei jest zależna od stopnia
skomplikowania programu szadera), a następnie określić wielkość trójkąta wy-
rażoną w ilości pikseli na niego przypadających. Można przyjąć, że im bardziej
skomplikowana jest dana scena, tym z mniejszych powierzchniowo trójkątów
się składa. Dla obu testowanych programów powierzchnia wypełnianej siatki
(siatkę należy wybrać taką, dla której ilość wyświetlanych klatek na sekundę
jest akceptowalna, w przypadku testowym jest to siatka typu XxYx5, dwie
pierwsze wartości nie mają znaczenia, ponieważ zawsze wyznaczają tą samą
powierzchnię) to ok. 80% powierzchni ekranu (629145 pikseli). Przyjmując za
trójkąt wzorcowy trójkąt o powierzchni 80 pikseli, maksymalna ilość trójką-
tów zapewniającą płynną animację dla komputera testowego wynosi ok. 7800
trójkątów. Wartość tą należy jeszcze zmniejszyć ze względu na obciążenie
procesora geometrii do ok. 5000-6000 trójkątów. Jest to wartość w zupełno-
ści wystarczająca do zamodelowania większości scen 3D i w pełni zaspoka-
ja wymagania dzisiejszych systemów czasu rzeczywistego (wykorzystywanych
głównie w grach).
3. Jakość generowanej grafiki była bardzo dobra. Podczas testów nie zauważono
żadnych zniekształceń i przekłamań w wyświetlanym obrazie. Renderowane
wielokąty były poddawane znacznemu oddaleniu i przybliżeniu w stosunku do
obserwatora. Były również ustawiane pod różnymi kątami widzenia.
62
6. Podsumowanie
Celem tej pracy było pokazanie, na ile reprogramowalne układy cyfrowe wspie-
rają proces teksturowania, a w szczególności proces teksturowania proceduralnego
i jaką wydajność w tym zakresie oferują. W niniejszej pracy:
— dokonano implementacji trzech programów cieniujących, w tym jednego, któ-
rego podstawą jest algorytm powszechnie wykorzystywany do syntezy tekstur
proceduralnych - szum K. Perlin’a,
— oszacowano wydajność aktualnie produkowanych układów graficznych,
— przedstawiono w szczegółowy sposób metody teksturowania w systemach cza-
su rzeczywistego oraz omówiono zalety i wady generowania tekstur procedu-
ralnych.
Jak wynika z pracy, możliwości dzisiejszych konstrukcji są już na tyle zaawan-
sowane, że wystarczają do implementacji większości metod proponowanych w
literaturze, a patrząc na dalsze plany produkcyjne największych producentów
kart graficznych, następne ich generacje będą oferować jeszcze większe możliwości,
powodując stopniowe zacieranie się granic między możliwościami standardowych
języków programowania, a językami jednostek cieniujących. Prawie nieograniczo-
na liczba instrukcji, dynamiczne sterowanie przebiegiem wykonywania programu
i większa liczba dostępnych funkcji matematycznych w bibliotece standardowej
pozwolą na napisanie praktycznie dowolnego programu. Można jedynie obawiać
się o wydajność takich konstrukcji. Jednak z przeprowadzonych testów widać,
że prędkość obecnych układów jest akceptowalna dla większości scen 3D i sza-
derów o liczbie instrukcji nie przekraczających pewnej granicy (96 dla ps 2.0).
Pozwala to dobrze rokować na przyszłość. Celem dalszych badań powinny być
nowe metody generowania tekstur proceduralnych, a także implementacja algo-
rytmów proponowanych już dziś (mozaika, droga wykładana kamieniami itp.),
które ze względu na stopień skomplikowania muszą poczekać na kolejne generacje
reprogramowalnych układów cyfrowych.
Literatura 63
Literatura
[1] J. D. Foley, A. van Dam, „Wprowadzenie do grafiki komputerowej”, WNT 1995.
[2] T.Moller, E. Haines, „Real-Time Rendering”, A K Peters, Ltd. 1999.
[3] M. Byggmastar, „Fast affine texture mapping”, 08.07.1996.
[4] Andreas Jonsson, „Texture Generator”, www.angelcode.com
[5] Ken Perlin Homepage, http://mrl.nyu.edu/ perlin
[6] Paul Bourke, „Perlin Noise and Turbulence”,
http://astronomy.swin.edu.au/ pbourke/texture/perlin, 2000.
[7] Hugo Elias, „Perlin Noise”, http://freespace.virgin.net/hugo.elias/models/m perlin.htm
[8] Daniel Kos, „Noise Generator v.1.0”, 2003.
[9] Mark Harris, „Reaction Diffusion”, 07.11.2002, http://www.cgshaders.org
[10] Arkadiusz Waliszewski, „Fractal”, 07.11.2002, http://www.cgshaders.org
[11] ATI Technologies Inc, „Clouds”,
http://www.ati.com/developer/samples/clouds.html
[12] ATI Technologies Inc, „Ocean Water”,
http://www.ati.com/developer/samples/oceanwater.html
[13] S. Lefebvre, F. Neyret, „Pattern Based Procedural Textures”,
iMAGIS*/GRAVIR-IMAG 2003
[14] B. Freudenberg, „Real-Time Stroke Textures”, Institut fur Simulation und Graphik
[15] Cg Toolkit, developer.nvidia.com
[16] A. Mine, F. Neyret, „Perlin Textures in Real Time using OpenGL”,
Institut National de Recherche En Informatique et en Automatique 1999
[17] J. Kautz, W. Heidrichy, „Real-Time Bump Map Synthesis”,
Max-Planck-Institut fur Informatik 2000
[18] ATI Technologies Inc, „HLSL FX”,
http://www.ati.com/developer/samples/dx9/HLSL FX.html
[19] W. Heidrich, P. Slusallek, H.P. Seidel, „Sampling of Procedural Shaders Using
Affine Arithmetic”, Univ. of Erlangen 1998
[20] David S. Ebert , F. Kenton Musgrave , D. Peachey , K. Perlin , S. Worley, „Te-
xturing and modeling: a procedural approach”, Academic Press Professional, Inc.,
San Diego, CA, 1994