Számítógépes Grafika Klár Gergely tremere@elte.hu Eötvös Loránd Tudományegyetem Informatikai Kar 2010/2011. őszi félév
Tartalom Vágás Szakaszvágás Poligonvágás 1 Vágás Szakaszvágás Poligonvágás 2
Vágás Szakaszvágás Poligonvágás 2D algoritmusokról beszélünk, általánosíthatók 3D-ra Mit akarunk vágni? pont szakasz poligon Mire akarunk vágni? poligon ablak, téglalap félsík
az ablakra Vágás Szakaszvágás Poligonvágás Pont vágás: (x, y) R 2. Akkor tartjuk meg a pontot, ha (x, y) [x min, x max ] [y min, y max ]. Megoldás: négy összehasonlítás. Szakasz vágás: a szakasznak csak azokat a pontjai akarjuk megtartani, amik benne vannak [x min, x max ] [y min, y max ]-ban. Megoldás: az ablak négy élével, mint négy félsíkkal vágjuk a szakaszt. Poligon vágás: a poligonból egy új poligont akarunk csinálni, ami nem lóg ki az ablakból. Megoldás: A poligon minden oldalát (mint szakaszt) vágjuk.
Szakasz vágása félsíkra Szakaszvágás Poligonvágás Félsík: egyenes + egy oldala Csak azt a speciális esetet nézzük, amikor a vágó egyenes párhuzamos valamelyik tengellyel. (x 1, y 1 ) (x 2, y 2 ) szakasz egyenlete: Vágó egyenes: pl. x = x min x(t) = x 1 + t(x 2 x 1 ) y(t) = y 1 + t(y 2 y 1 ) Megoldás: x min = x 1 + t(x 2 x 1 ) t = x min x 1 x 2 x 1 Metszéspont: x = x min, y = y 1 + x min x 1 x 2 x 1 (y 2 y 1 )
Szakasz vágása - nehézségek Szakaszvágás Poligonvágás Eredmény kezelése: t 0 vagy t 1 nincs is igazi vágás. Kivételek: tengelyekkel párhuzamos szakaszok vágása. Rengeteg eset: négy félsík, két végpont, mindkettő eshet bárhova. Feladat: Kell-e vágni? Melyik félsík(ok)ra kell vágni? Triviálisan bent/kint van-e a szakasz? Megoldás: Cohen Sutherland vágás
Cohen Sutherland vágás Szakaszvágás Poligonvágás Az egyenesekkel osszuk kilenc részre a síkot! Mindegyikhez rendeljünk egy bit-kódot: TBRL Számítsuk ki ezt a kódot a szakasz végpontjaira! T - 1, ha a pont az ablak fölött van B -1, ha a pont az ablak alatt van R -1, ha a pont az ablaktól jobbra van L -1, ha a pont az ablaktól balra van
Cohen Sutherland vágás Szakaszvágás Poligonvágás code = Top, Bottom, Right, Left
Cohen Sutherland vágás Szakaszvágás Poligonvágás code = (y > y max, y < y min, x > x max, x < x min ) Vizsgáljuk a két végpont bit-kódjait, code a -t és code b -t! Ha code a OR code b == 0: a szakasz az ablakban van megtartjuk. Ha code a AND code b!= 0: a szakasz az ablak valamelyik oldalán (fölül, alul, jobbra, balra), kívül van eldobjuk. Különben vágni kell: az 1-es bitek adják meg, hogy melyik félsíkra, utána újra számoljuk a bit-kódokat, és az új szakasszal újrakezdjük az algoritmust.
Cohen Sutherland vágás Szakaszvágás Poligonvágás code a OR code b == 0:
Cohen Sutherland vágás Szakaszvágás Poligonvágás code a AND code b!= 0:
Cohen Sutherland vágás Szakaszvágás Poligonvágás Különben:
Poligonvágás Vágás Szakaszvágás Poligonvágás Feladat Adott egy vágandó és egy vágó poligon. Keressük azt a poligont, amit a vágandóból kapunk, ha csak a vágó poligonba tartozó részeit vesszük. Röviden: keressük a kettő közös részét. Algoritmusok: Sutherland Hodgman: convex vágó poligon, convex vágandónál hibák; gyorsabb Weiler Atherton: nem önmetsző poligonokra; lassabb, nem vesszük
Szakaszvágás Poligonvágás Sutherland-Hodgeman poligonvágás Legyen p tömb a bemeneti-, q a kimeneti-poligon csúcsainak tömbje! Legyen n a csúcsok száma, és p[0] = p[n]! Vágás egyenesre: Ha p[i] bent van az alablakban, és p[i + 1] is: adjuk hozzá p[i]-t a q-hoz. Ha p[i] bent van az alablakban, de p[i + 1] nincs: adjuk hozzá p[i]-t a q-hoz, számítsuk ki p[i], p[i + 1] szakasz metszéspontját a vágó egyenessel, majd ezt is adjuk hozzá q-hoz. Ha p[i] nincs bent az alablakban, de p[i + 1] benne van: számítsuk ki p[i], p[i + 1] szakasz metszéspontját a vágó egyenessel, és ezt adjuk hozzá q-hoz. Ha p[i] nincs bent az alablakban, és p[i + 1] sincs: SKIP
Szakaszvágás Poligonvágás Sutherland-Hodgeman poligonvágás - Pszedudó kód PolygonClip(in p[n], out q[m], in line) { m = 0; for( i=0; i < n; i++) { if (IsInside(p[i])) { q[m++] = p[i]; if (!IsInside(p[i+1])) q[m++] = Intersect(p[i], p[i+1], line); } else { if (IsInside(p[i+1])) q[m++] = Intersect(p[i], p[i+1], line); } } }
Szakaszvágás Poligonvágás Sutherland-Hodgeman: konkáv poligonok Konkáv poligonokra átfedő éleket hoz létre.
Szakaszvágás Poligonvágás Sutherland-Hodgeman: konkáv poligonok Konkáv poligonokra átfedő éleket hoz létre.
Szakaszvágás Poligonvágás Sutherland-Hodgeman: konkáv poligonok Konkáv poligonokra átfedő éleket hoz létre.
Szakaszvágás Poligonvágás Sutherland-Hodgeman: konkáv poligonok Konkáv poligonokra átfedő éleket hoz létre.
Szakaszvágás Poligonvágás Sutherland-Hodgeman: konkáv poligonok Konkáv poligonokra átfedő éleket hoz létre.
Szakaszvágás Poligonvágás Sutherland-Hodgeman: konkáv poligonok Konkáv poligonokra átfedő éleket hoz létre.
Szakaszvágás Poligonvágás Sutherland-Hodgeman: konkáv poligonok Konkáv poligonokra átfedő éleket hoz létre.
Szakaszvágás Poligonvágás Sutherland-Hodgeman: konkáv poligonok Konkáv poligonokra átfedő éleket hoz létre.
Tartalom Vágás 1 Vágás 2
Szakasz rajzolás Vágás Egyik leggyakrabb primitív. Fontos, hogy szépen tudjuk rajzolni. Mégjobb, ha gyorsan is. Jason Thielke, jasonthielke.com
Hogyan rajzolunk szakaszt? Adott a két végpont. Hogyan tudjuk összekötni őket? Csak miniatűr téglalapjaink vannak (amiket pixelnek nevezünk).
Hogyan rajzolunk szakaszt? Adott a két végpont. Hogyan tudjuk összekötni őket? Csak miniatűr téglalapjaink vannak (amiket pixelnek nevezünk).
Hogyan rajzolunk szakaszt? Adott a két végpont. Hogyan tudjuk összekötni őket? Csak miniatűr téglalapjaink vannak (amiket pixelnek nevezünk).
Hogyan rajzolunk szakaszt? Adott a két végpont. Hogyan tudjuk összekötni őket? Csak miniatűr téglalapjaink vannak (amiket pixelnek nevezünk).
Hogyan rajzolunk szakaszt? Adott a két végpont. Hogyan tudjuk összekötni őket? Csak miniatűr téglalapjaink vannak (amiket pixelnek nevezünk).
Szakasz megadása (sokadszor) Végpontok: (x 1, y 1 ), (x 2, y 2 ) Tfh. nem függőleges: x 1 x 2. Szakasz egyenlete: y = mx + b, x [x 1, x 2 ] m = y 2 y 1 x 2 x 1 b = y 1 mx 1
Naív algoritmus Vágás def l i n e 1 ( x1, y1, x2, y2, draw ) : m = f l o a t ( y2 y1 ) / ( x2 x1 ) x = x1 y = f l o a t ( y1 ) while x<=x2 : draw. p o i n t ( ( x, y ) ) x += 1 y += m
Naív algoritmus Vágás m = float(y2-y1)/(x2-x1) nem pontos y += m a hiba gyűlik y-ban draw.point((x,y)) int-eket vár, lassú a konverzió csak m < 1-re működik helyesen
Naív algoritmus Vágás m = float(y2-y1)/(x2-x1) nem pontos y += m a hiba gyűlik y-ban draw.point((x,y)) int-eket vár, lassú a konverzió csak m < 1-re működik helyesen
Naív algoritmus Vágás m = float(y2-y1)/(x2-x1) nem pontos y += m a hiba gyűlik y-ban draw.point((x,y)) int-eket vár, lassú a konverzió csak m < 1-re működik helyesen
Naív algoritmus Vágás m = float(y2-y1)/(x2-x1) nem pontos y += m a hiba gyűlik y-ban draw.point((x,y)) int-eket vár, lassú a konverzió csak m < 1-re működik helyesen
Naív algoritmus Vágás m = float(y2-y1)/(x2-x1) nem pontos y += m a hiba gyűlik y-ban draw.point((x,y)) int-eket vár, lassú a konverzió csak m < 1-re működik helyesen
Javítsuk az algoritmust 1. def l i n e 2 ( x1, y1, x2, y2, draw ) : m = f l o a t ( y2 y1 ) / ( x2 x1 ) x = x1 y = y1 e = 0.0 while x<=x2 : draw. p o i n t ( ( x, y ) ) x += 1 e += m i f e >= 0. 5 : y += 1 e = 1.0
Javítsuk az algoritmust 1. Naív: Jó: Mindig eltalálja a végpontokat Jó: Egyenletesebben lép az y irányban. Rossz: Még mindig használunk float-okat Javítás:
Javítsuk az algoritmust 2. def l i n e 3 ( x1, y1, x2, y2, draw ) : x = x1 y = y1 e = 0.5 while x<=x2 : draw. p o i n t ( ( x, y ) ) x += 1 e += i f f l o a t ( y2 y1 ) / ( x2 x1 ) e >= 0. 0 : y += 1 e = 1.0
Javítsuk az algoritmust 3. def l i n e 4 ( x1, y1, x2, y2, draw ) : x = x1 y = y1 e = 0.5 ( x2 x1 ) while x<=x2 : draw. p o i n t ( ( x, y ) ) x += 1 e += y2 y1 i f e >= 0. 0 : y += 1 e = ( x2 x1 )
Javítsuk az algoritmust 4. def l i n e 5 ( x1, y1, x2, y2, draw ) : x = x1 y = y1 e = (x2 x1 ) while x<=x2 : draw. p o i n t ( ( x, y ) ) x += 1 e += 2 ( y2 y1 ) i f e >= 0: y += 1 e = 2 ( x2 x1 )
Javítsuk az algoritmust 4. Ez a Bresenham algoritmus (egyik speciális esete) Külön gyűjtjük a hibát e-ben Nem használunk float-okat Tetszőleges meredekségű szakaszokra általánosítható.
Bresenham algoritmus Nyolcadokra kéne felbontani a síkot, mindegyik külön eset. (Előzők végig: jobbra-le) El kell döntenünk, hogy x 2 x 1 vagy y 2 y 1 a nagyobb (merre meredekebb a szakasz). Ha y 2 y 1 a nagyobb, cseréljük fel x i y i, és rajzolásnál is fordítva használjuk! Ha x 1 > x 2, akkor csere: x 1 x 2, y 1 y 2. Az e hibatagot y 2 y 1 -nal növeljük minden lépésben y-nal y 2 y 1 előjele szerint haladunk.
Bresenham algoritmus
Teljes Bresenham algoritmust 1. def Bresenham ( x1, y1, x2, y2, draw ) : steep = abs ( y2 y1)>abs ( x2 x1 ) i f steep : x1, y1 = y1, x1 x2, y2 = y2, x2 i f x1>x2 : x1, x2 = x2, x1 y1, y2 = y2, y1 Dy = abs ( y2 y1 ) i f y1<y2 : Sy = 1 else : Sy = 1
Teljes Bresenham algoritmust 2. x = x1 y = y1 e = (x2 x1 ) while x<=x2 : i f steep : draw. p o i n t ( ( y, x ) ) else : draw. p o i n t ( ( x, y ) ) x += 1 e += 2 Dy i f e >= 0: y += Sy e = 2 ( x2 x1 )
Flood-fill elárasztásos kitöltés Tetszőleges, már raszterizált poligon kitöltésére alkalmas. Bemenet: raszter kép + annak egy pontja A megadott pontból kiindulva rekurzívan haladunk: Az aktuális pont színe megegyezik a kiindulási pont színével? nem megállunk igen átszínezzük, és minden szomszédra újrakezdjük az algoritmust.
Flood-fill szomszédásgok Négy szomszéd: fent, lent, jobbra, balra Nyolc szomszéd: az előző négy + a sarkak
Háromszög kitöltés Vágás Nem egy rögzített értékkel akarunk kitölteni, a hanem a csúcsokban adott értékeket akarjuk interpolálni. Felhasználásai: szín (Gouraud-árnyalás), textúra koordinták, normálvektorok Legyen a felület egy pontja p = αp 1 + βp 2 + γp 3, az α, β, γ baricentrikus koordinátákkal adott. Ekkor bármilyen más értéket is végig tudunk interpolálni ugyan így: c = αc 1 + βc 2 + γc 3 Ez az úgy nevezett Gouraud interpoláció (nem véletlenül)
Háromszög kitöltés 1. Vágás f o r a l l x : f o r a l l y : α, β, γ = b a r y c e n t r i c ( x, y ) i f α [0, 1] and β [0, 1] and γ [0, 1] : c = αc 1 + β c 2 + γ c 3 draw. p o i n t ( ( x, y ), c )
Baricentrikus koordináták A baricentrikus koordináták számíthatók a következő képletekkel: f 01 (x, y) = (y 0 y 1 )x + (x 1 x 0 )y + x 0 y 1 x 1 y 0 f 12 (x, y) = (y 1 y 2 )x + (x 2 x 1 )y + x 1 y 2 x 2 y 1 f 20 (x, y) = (y 2 y 0 )x + (x 0 x 2 )y + x 2 y 0 x 0 y 2 Ekkor az x, y ponthoz tartozó baricentrikus koordináták: α = f 12 (x, y)/f 12 (x 0, y 0 ) β = f 20 (x, y)/f 20 (x 1, y 1 ) γ = f 01 (x, y)/f 01 (x 2, y 2 )
Háromszög kitöltés 2. Vágás x min = min ( f l o o r ( x i ) ) x max = max( c e i l i n g ( x i ) ) y min = min ( f l o o r ( y i ) ) y max = max( c e i l i n g ( y i ) ) f o r y i n [ y min.. y max ] : f o r x i n [ x min.. x max ] : α = f 12 (x, y)/f 12 (x 0, y 0 ) β = f 20 (x, y)/f 20 (x 1, y 1 ) γ = f 01 (x, y)/f 01 (x 2, y 2 ) i f α>0 and β>0 and γ >0: c = αc 1 + β c 2 + γ c 3 draw. p o i n t ( ( x, y ), c )
Háromszög kitöltés 2. Vágás Gyorsítás: felesleges minden x, y-t vizsgálni, elég a háromszöget tartalazó téglalapon végig menni. Inkrementálissátétel: Most még lassú, nem használjuk, ki hogy sorban megyünk x-en, y-on. Milyenek is ezek az f -ek? Mind f (x, y) = Ax + By + C alakú. Ekkor f (x + 1, y) = f (x, y) + A, ill. f (x, y + 1) = f (x, y) + B Megvalósítás:
Háromszög kitöltés 2. Vágás Gyorsítás: felesleges minden x, y-t vizsgálni, elég a háromszöget tartalazó téglalapon végig menni. Inkrementálissátétel: Most még lassú, nem használjuk, ki hogy sorban megyünk x-en, y-on. Milyenek is ezek az f -ek? Mind f (x, y) = Ax + By + C alakú. Ekkor f (x + 1, y) = f (x, y) + A, ill. f (x, y + 1) = f (x, y) + B Megvalósítás:
Háromszög kitöltés 2. Vágás Gyorsítás: felesleges minden x, y-t vizsgálni, elég a háromszöget tartalazó téglalapon végig menni. Inkrementálissátétel: Most még lassú, nem használjuk, ki hogy sorban megyünk x-en, y-on. Milyenek is ezek az f -ek? Mind f (x, y) = Ax + By + C alakú. Ekkor f (x + 1, y) = f (x, y) + A, ill. f (x, y + 1) = f (x, y) + B Megvalósítás:
Háromszög kitöltés 2. Vágás Gyorsítás: felesleges minden x, y-t vizsgálni, elég a háromszöget tartalazó téglalapon végig menni. Inkrementálissátétel: Most még lassú, nem használjuk, ki hogy sorban megyünk x-en, y-on. Milyenek is ezek az f -ek? Mind f (x, y) = Ax + By + C alakú. Ekkor f (x + 1, y) = f (x, y) + A, ill. f (x, y + 1) = f (x, y) + B Megvalósítás:
Háromszög kitöltés 2. Vágás Gyorsítás: felesleges minden x, y-t vizsgálni, elég a háromszöget tartalazó téglalapon végig menni. Inkrementálissátétel: Most még lassú, nem használjuk, ki hogy sorban megyünk x-en, y-on. Milyenek is ezek az f -ek? Mind f (x, y) = Ax + By + C alakú. Ekkor f (x + 1, y) = f (x, y) + A, ill. f (x, y + 1) = f (x, y) + B Megvalósítás:
Háromszög kitöltés 2. Vágás Gyorsítás: felesleges minden x, y-t vizsgálni, elég a háromszöget tartalazó téglalapon végig menni. Inkrementálissátétel: Most még lassú, nem használjuk, ki hogy sorban megyünk x-en, y-on. Milyenek is ezek az f -ek? Mind f (x, y) = Ax + By + C alakú. Ekkor f (x + 1, y) = f (x, y) + A, ill. f (x, y + 1) = f (x, y) + B Megvalósítás: házi feladat