teksturowanie obiektów z wykorzystaniem reprogramowalnych

63
Wydzial Informatyki Politechnika Szczecińska Praca magisterska Teksturowanie obiektów z wykorzystaniem reprogramowalnych modulów do obliczania cieniowania Daniel Kos promotor: dr inż. Radoslaw Mantiuk Szczecin 2003

Upload: habao

Post on 11-Jan-2017

218 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Teksturowanie obiektów z wykorzystaniem reprogramowalnych

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

Page 2: Teksturowanie obiektów z wykorzystaniem reprogramowalnych

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

Page 3: Teksturowanie obiektów z wykorzystaniem reprogramowalnych

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

Page 4: Teksturowanie obiektów z wykorzystaniem reprogramowalnych

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)

Page 5: Teksturowanie obiektów z wykorzystaniem reprogramowalnych

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

Page 6: Teksturowanie obiektów z wykorzystaniem reprogramowalnych

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

Page 7: Teksturowanie obiektów z wykorzystaniem reprogramowalnych

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

Page 8: Teksturowanie obiektów z wykorzystaniem reprogramowalnych

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

Page 9: Teksturowanie obiektów z wykorzystaniem reprogramowalnych

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.

Page 10: Teksturowanie obiektów z wykorzystaniem reprogramowalnych

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

Page 11: Teksturowanie obiektów z wykorzystaniem reprogramowalnych

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

Page 12: Teksturowanie obiektów z wykorzystaniem reprogramowalnych

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 ;

Page 13: Teksturowanie obiektów z wykorzystaniem reprogramowalnych

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

Page 14: Teksturowanie obiektów z wykorzystaniem reprogramowalnych

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

Page 15: Teksturowanie obiektów z wykorzystaniem reprogramowalnych

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

Page 16: Teksturowanie obiektów z wykorzystaniem reprogramowalnych

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

Page 17: Teksturowanie obiektów z wykorzystaniem reprogramowalnych

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

Page 18: Teksturowanie obiektów z wykorzystaniem reprogramowalnych

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

Page 19: Teksturowanie obiektów z wykorzystaniem reprogramowalnych

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-

Page 20: Teksturowanie obiektów z wykorzystaniem reprogramowalnych

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

Page 21: Teksturowanie obiektów z wykorzystaniem reprogramowalnych

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

Page 22: Teksturowanie obiektów z wykorzystaniem reprogramowalnych

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

Page 23: Teksturowanie obiektów z wykorzystaniem reprogramowalnych

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

Page 24: Teksturowanie obiektów z wykorzystaniem reprogramowalnych

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.

Page 25: Teksturowanie obiektów z wykorzystaniem reprogramowalnych

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

Page 26: Teksturowanie obiektów z wykorzystaniem reprogramowalnych

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

Page 27: Teksturowanie obiektów z wykorzystaniem reprogramowalnych

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-

Page 28: Teksturowanie obiektów z wykorzystaniem reprogramowalnych

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

Page 29: Teksturowanie obiektów z wykorzystaniem reprogramowalnych

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

Page 30: Teksturowanie obiektów z wykorzystaniem reprogramowalnych

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:

Page 31: Teksturowanie obiektów z wykorzystaniem reprogramowalnych

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

Page 32: Teksturowanie obiektów z wykorzystaniem reprogramowalnych

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

Page 33: Teksturowanie obiektów z wykorzystaniem reprogramowalnych

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ń.

Page 34: Teksturowanie obiektów z wykorzystaniem reprogramowalnych

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).

Page 35: Teksturowanie obiektów z wykorzystaniem reprogramowalnych

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.

Page 36: Teksturowanie obiektów z wykorzystaniem reprogramowalnych

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

Page 37: Teksturowanie obiektów z wykorzystaniem reprogramowalnych

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.

Page 38: Teksturowanie obiektów z wykorzystaniem reprogramowalnych

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.

Page 39: Teksturowanie obiektów z wykorzystaniem reprogramowalnych

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.

Page 40: Teksturowanie obiektów z wykorzystaniem reprogramowalnych

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].

Page 41: Teksturowanie obiektów z wykorzystaniem reprogramowalnych

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.

Page 42: Teksturowanie obiektów z wykorzystaniem reprogramowalnych

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

Page 43: Teksturowanie obiektów z wykorzystaniem reprogramowalnych

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)

Page 44: Teksturowanie obiektów z wykorzystaniem reprogramowalnych

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)

Page 45: Teksturowanie obiektów z wykorzystaniem reprogramowalnych

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

Page 46: Teksturowanie obiektów z wykorzystaniem reprogramowalnych

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

Page 47: Teksturowanie obiektów z wykorzystaniem reprogramowalnych

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

Page 48: Teksturowanie obiektów z wykorzystaniem reprogramowalnych

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

Page 49: Teksturowanie obiektów z wykorzystaniem reprogramowalnych

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 ;

Page 50: Teksturowanie obiektów z wykorzystaniem reprogramowalnych

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-

Page 51: Teksturowanie obiektów z wykorzystaniem reprogramowalnych

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

Page 52: Teksturowanie obiektów z wykorzystaniem reprogramowalnych

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 ∗/

Page 53: Teksturowanie obiektów z wykorzystaniem reprogramowalnych

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.

Page 54: Teksturowanie obiektów z wykorzystaniem reprogramowalnych

4.2 Generator cząsteczek 54

Rysunek 53. Rezultat działania programu Particles

Page 55: Teksturowanie obiektów z wykorzystaniem reprogramowalnych

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 ∗/

Page 56: Teksturowanie obiektów z wykorzystaniem reprogramowalnych

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.

Page 57: Teksturowanie obiektów z wykorzystaniem reprogramowalnych

4.3 Generator komórek 57

Rysunek 55. Rezultat działania programu Cells

Page 58: Teksturowanie obiektów z wykorzystaniem reprogramowalnych

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))

Page 59: Teksturowanie obiektów z wykorzystaniem reprogramowalnych

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

Page 60: Teksturowanie obiektów z wykorzystaniem reprogramowalnych

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.

Page 61: Teksturowanie obiektów z wykorzystaniem reprogramowalnych

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.

Page 62: Teksturowanie obiektów z wykorzystaniem reprogramowalnych

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.

Page 63: Teksturowanie obiektów z wykorzystaniem reprogramowalnych

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