Tietokonegrafiikan perusteet T-111.4300 3 op Luento : Viivan toteutus Lauri Savioja 11/07 Primitiivien toteutus / 1 GRAAFISTEN PRIMITIIVIEN TOTEUTUS HUOM! Oletuksena on XY-koordinaatisto Suorien viivojen piirtäminen Malli piirturikynällä piirtämisestä Kynä on aina jossakin (CP = Current Position) Inkrementaaliset alkeisoperaatiot: PenUp / PenDown CP' = CP + (±1, ±1)-> 8 eri askelta Primitiivien toteutus / 1
Piirtäminen rasteriruudulle Alkeisoperaationa: SetPixel ( x, y, color ) Pisteet piirrettävissä missä järjestyksessä hyvänsä Koordinaatit suhteellisina määritellyn rasterin origoon nähden Primitiivien toteutus / 3 Laskennallisia vaatimuksia Nopea, eli kokonaislukuja yhteen- ja vähennyslaskuja shiftejä Hitaita asioita kertolaskut reaaliluvut kirjastofunktiot, esim. trigonometriset operaatiot Primitiivien toteutus / 4
Suoran viivan vaatimukset Suora Tasapaksu (tasainen intensiteetti) Portaaton Täsmällinen alku ja loppu Intensiteetti riippumaton pituudesta ja kulmakertoimesta Primitiivien toteutus / 5 Algoritmi suoran piirtämiseksi Suoran yhtälö y=ax+b Alkupiste (x o,y o ), loppupiste (x 1,y 1 ) Primitiivien toteutus / 6 3
DDA (Digital Differential Analyzer) - algoritmi Periaate: pisteitä suoralla voidaan laskea esim. janan päätepisteiden (p 1, p ) avulla esitetystä parametrimuodosta p(t) = p 1 + t * p = p 1 + t * (p - p 1 ) ; t [0,1] x(t) = x 1 + t * X y(t) = y 1 + t * Y = y 1 + m * (t * X) ; m = Y / X eli antamalla t:lle sopivia arvoja ja pyöristämällä lasketut koordinaatit. Primitiivien toteutus / 7 DDA (jatkuu) raa an voiman menetelmä : iteroidaan t-parametria riittävän pienin askelin, jotta kaikki "janalla olevat" (so. lähellä olevat) pisteet tulevat käytyä läpi. DDA : iteroidaan yksikköaskelin sitä koordinaattia, jonka siirtymä on suurempi, esim. x increment = ±1 ja y increment = m, kun m < 1. heikkouksia: jakolasku alussa liukuluvut, pyöristys joka pisteessä Primitiivien toteutus / 8 4
Viivanpiirto SIGGRAPH opetusdiat Primitiivien toteutus / 9 Bresenham PASCAL-kielisenä: procedure bres_line (x1, y1, x, y : integer); var dx, dy, x, y, x_end, p, const1,const : integer; dx := abs(x1 - x); dy := abs(y1 - y); p := * dy - dx; const1 := * dy; const := * (dy - dx); if x1 > x then { if x1 > x } x := x; y := y; x_end := x1 end else { if x1 <= x } x := x1; y := y1; x_end := x set_pixel(x, y); while x < x_end do x := x + 1; if p < 0 then p := p + const1 else y := y + 1; p := p + const set_pixel(x, y) end Primitiivien toteutus / 10 5
Bresenham (jatkuu) algoritmin edut: ei lainkaan jakolaskua eikä liukulukuja kertolasku vain tekijällä (= bin.luvun sivuttaissiirto) Huom. algoritmi johdettu nousevalle suoralle, dx>0, m < 1. Jos dx < 0, vaihdetaan päätepisteet (p 1, p ) keskenään, tai päivitetään x-arvoa -1:n askelin laskevalle suoralle, -1 < m < 0, vaihdetaan y:n askeleeksi -1 Jos m > 1, vaihdetaan x:n ja y:n roolit keskenään. Primitiivien toteutus / 11 KÄYRÄT VIIVAT suorien ohella tarvitaan usein myös käyriä: käyrät (ympyrän, ellipsin, parabelin kaaret) splinit (myöhemmin tällä kurssilla) periaatteessa mikä hyvänsä käyrä voidaan approksimoida murtoviivalla, mutta tehokkaampaa on yleensä tuottaa käyrän pisteet suoraan sen määritelmästä DDA-algoritmi ja Bresenhamin muunnelma siitä ovat helposti muunnettavissa monille käyrille sopiviksi, mutta on varottava äärellisestä differenssiaskeleesta aiheutuvaa virhettä. Primitiivien toteutus / 1 6
Bresenhamin ympyränpiirtoalgoritmi symmetrian ansiosta riittää tarkastella vain kahdeksasosaa koko ympyrästä; loput pisteet saadaan vaihtamalla x:n ja y:n rooleja ja etumerkkejä (olettaen, että keskipiste on origossa): -x,y x,y -y,x y,x -y,-x y,-x -x,-y x,-y piirtäminen alkaa pisteestä (0,r) ja päättyy, kun x=y. Primitiivien toteutus / 13 Ympyrä (jatkuu) Tarkastellaan askelta i, jossa ollaan viimeksi piirretty piste (x i, y i ), ja seuraavaksi on pääteltävä kumpi pisteistä, (x i +1, y i ) vai (x i +1, y i 1), on lähempänä todellista käyrän pistettä (x i +1, y exact ) : y exact yi y i-1 d1 d xi xi+1 Primitiivien toteutus / 14 7
Ympyrä (jatkuu) ympyrän yhtälöstä y = r x saadaan: y exact = r (x i + 1), jota voidaan verrata vaihtoehtoisiin pisteisiin: d 1 = y i y exact = y i r + (x i + 1), d = y exact (y i - 1) = r (x i + 1) (y i - 1) p i = d 1 d = (x i + 1) + y i + (y i - 1) r valitaan se piste, jonka etäisyys oikeasta on pienempi, eli jos parametri p i < 0, niin valitaan arvo y i, muuten arvo (y i - 1). Primitiivien toteutus / 15 Ympyrä (jatkuu) Parametrin p arvo seuraavassa pisteessä (x i +1, y i+1 ) voidaan laskea iteratiivisesti edellisessä pisteessä lasketusta arvosta. Edellä laskettua lauseketta muokkaamalla saadaan: p i+1 = [(x i +1) + 1] + y i+1 + (y i+1-1) r = p i + 4x i + 6 + (y i +1 - y i ) (y i+1 - y i ) = p i + 4x i + 6, jos y i+1 = y i = p i + 4x i + 6 4y i + 4, jos y i+1 = y i + 1 aloituspisteessä (0, r) lauseke on: p 1 = 3 r. Primitiivien toteutus / 16 8
Ympyräkoodi procedure bres_circle (x_center, y_center, radius : integer); var p, x, y : integer; procedure plot_circle_points; { 8 symmetric positions } set_pixel(x_center + x, y_center + y); set_pixel(x_center - x, y_center + y); set_pixel(x_center + x, y_center - y); set_pixel(x_center - x, y_center - y); set_pixel(x_center + y, y_center + x); set_pixel(x_center - y, y_center + x); set_pixel(x_center + y, y_center - x); set_pixel(x_center - y, y_center - x) Primitiivien toteutus / 17 Ympyräkoodi (jatkuu) { bres_circle } x := 0; y := radius; p := 3 - * radius; while x < y do plot_circle_points; if p < 0 then p := p + 4 * x + 6 else p := p + 4 * (x - y) + 10; y := y - 1; x := x + 1; end if x = y then plot_circle_points; Primitiivien toteutus / 18 9