opengl es: 3d fraktali -...
TRANSCRIPT
SVEUČILIŠTE U ZAGREBU
FAKULTET ORGANIZACIJE I INFORMATIKE
VARAŽDIN
Gabrijel Bartošek
Samuel Picek
OPENGL ES: 3D FRAKTALI
SEMINARSKI RAD IZ KOLEGIJA RAČUNALNA GRAFIKA
Varaždin, 2015.
SVEUČILIŠTE U ZAGREBU
FAKULTET ORGANIZACIJE I INFORMATIKE
VARAŽDIN
Gabrijel Bartošek, 42642/13-R
Samuel Picek, 42632/13-R
OPENGL ES: 3D FRAKTALI
SEMINARSKI RAD IZ KOLEGIJA RAČUNALNA GRAFIKA
Mentor:
Doc. dr. sc. Ivan Hip
Prof. Damir Horvat
Varaždin, siječanj 2015.
I
Sadržaj 1.Uvod ........................................................................................................................................ 1
2.Povijest fraktala ....................................................................................................................... 2
3.Definicija fraktala .................................................................................................................... 4
3.1.Podjela fraktala ................................................................................................................. 5
3.2.Primjena fraktala ............................................................................................................ 12
3.3.Fraktalna dimenzija ........................................................................................................ 14
4.Prikaz grafike s OpenGL ES ................................................................................................. 17
4.1.Izgradnja OpenGL ES okruženja ................................................................................... 17
4.1.1.Deklariranje OpenGL koristeći Manifest ................................................................ 17
4.1.2.Kreiranje aktivnosti za OpenGL ES grafiku ........................................................... 18
4.1.3.Gradnja GLSSurfaceView objekata ........................................................................ 18
4.1.4.Gradnja Renderer klase (klasa prikazivanja) .......................................................... 20
4.2.Definiranje oblika ........................................................................................................... 21
4.2.1.Primjer definiranja trokuta ...................................................................................... 21
4.2.2.Primjer definiranja kvadrata .................................................................................... 22
4.3.Crtanje oblika ................................................................................................................. 24
4.3.1.Inicijalizacija oblika ................................................................................................ 24
4.3.2.Crtanje oblika .......................................................................................................... 25
4.4.Primjena projekcije i pogled kamere .............................................................................. 26
4.4.1. Definiranje projekcije ............................................................................................. 27
4.4.2. Definiranje pogleda kamere ................................................................................... 27
4.5. Dodavanje pokreta ......................................................................................................... 28
4.5.1.Rotiranje oblika ....................................................................................................... 28
4.5.2. Omogućavanje kontinuiranog prikazivanja (renderiranja)..................................... 29
5. Prikaz grafike s OpenGL ES iz Processinga 2.0 .................................................................. 30
5.1. Geometrijske transformacije ......................................................................................... 31
5.1.1. Translacija .............................................................................................................. 32
5.1.2. Rotacija ................................................................................................................... 33
5.1.3. Skaliranje ................................................................................................................ 35
5.2. Kamera i perspektiva ..................................................................................................... 36
5.3. Stvaranje 3D objekata ................................................................................................... 39
5.3.1. Teksture .................................................................................................................. 41
5.3.2. Svijetlo ................................................................................................................... 43
6. Kochova pahulja u 3D .......................................................................................................... 46
6.1. Analiza izvornog koda................................................................................................... 48
II
6.2. Analiza različitih dubina rekurzije ................................................................................ 53
7. Zaključak .............................................................................................................................. 57
Literatura .................................................................................................................................. 58
1
1.Uvod
Jedno od zanimljivijih područja računalne grafike zauzimaju matematičke umotvorine,
tj. fraktali. Cijeli svijet oko nas, te unutar nas zapravo je i sačinjen od nekakvoga vida
fraktala, a mogli bi slobodno reći da je i metodika našeg razmišljanja fraktalna.
U davnoj prošlosti matematika je bila pretežito orijentirana na skupove i funkcije nad kojima
su se pretežito primjenjivale metode klasičnog diferencijalnog računa. Skupovi funkcija koji
nisu bili dovoljno glatki ili regularni, pretežito su se ignorirali. U posljednjim desetljećima
ovakav se način razmišljanja uvelike promijenio.
Fraktali su čudesni geometrijski oblici koji se sastoje od umanjenih verzija samih sebe
(svaki dio je umanjena kopija cjeline). Nalazimo ih posvuda oko nas, te ih vidimo svaku dan,
mada ih ne primjemjećujemo. Možemo ih zapaziti na običnoj brokuli, cvjetači, ali isto tako u
planinskim lancima, te deltama rijeka. No međutim osim onih u prirodi, mi ćemo se u
seminarskom radu fokusirati na one fraktale koje stvara čovjek, kako bi se umjetnički i
vizualno posebno izrazio.
Prvenstveno fraktalna umjetnost je ona umjetnost koja nastaje uz pomoć računala i
matematike. Fraktalna geometrija nam daje generalni okvir gdje se proučavaju iregularni
skupovi. Premda dosta često u današnjici čujemo riječ fraktali, velika većina neće razumjeti
što oni točno predstavljaju i što znače. Bilo je mnogo pokušaja da se fraktali definiraju u čisto
matematičkom smislu, no te definicije često su se ispostavile neispravnima u općem smislu
značenja. Međutim, fraktalna geometrija daje podosta tehnika za upravljanje fraktalima.
2
2.Povijest fraktala
Kao što smo u uvodu naveli, fraktali koje stvara čovjek nastaju pomoću računala i
matematike. Računala danas pronalaze mnogobrojne primjene povezujući grafiku i
matematiku u pogledu umjetnosti, npr. digitalno obrađene fotografije i dizajn. S prvom
pojavom računala, umjetnici su se zapitkivali na koji način bi mogli iskoristiti taj novitet u
svom području, tj. za izradu svojih radova.
Računala koja su prva našla svoju primjenu u aspektu našeg privatnog, ali i poslovnog
života, zasigurno su našla svoju primjenu i u umjetnosti, tako da danas već koristimo izraz za
to „digitalna umjetnost“. Takva umjetnost je izazvana uz pomoć računala, a na to možemo
gledati kao sredstvo, odn. materijal i tehniku u isto vrijeme baš kao što su slikaru kist, boje i
platno. Poput fraktalnog umjetnika, kipara ili bilo koga drugog umjetnika, potrebna su
pomoćna sredstva da bi stvorili umjetničko djelo, no bez vlastite kreativnosti i rada to ne bi
moglo proizlaziti.
Fraktali su ljudima poznati od pamtivijeka, samo što se oni na taj način nisu
prepoznavali. Prvi dokumentirani prikaz fraktala možemo naći već 1525. god. u „Priručniku
za slikanje“ Albrechta Dürera gdje se opisuju uzorci nastali korištenjem pentagona. U 17. st.
Leibnitz je definirao ponavljanje samosličnosti, no međutim uzeo je u obzir da samo linija
može biti sebi slična. Od tada, pa do 19.st. nisu se javljale nikakve slične definicije. Tek 1872.
god. Karl Weierstrass daje primjer funkcije kojom je definirao samosličnost. Takva definicija
je bila suviše apstraktna, pa je Helge von Koch 1904. god. dao geometrijsku interpretaciju
slične funkcije, koja je danas poznata kao Kochova pahulja, a to će nam ujedno biti i
projektni zadatak iz ovog kolegija. Poslije toga 1915. god. Waclaw Sierpinski kreirao je svoj
uzorak fraktala pomoću trokuta. U tome razdoblju pronalazimo dosta fraktalnih prikaza poput
onih Pierrea Fatoua, Henria Poincaréa, Georgea Cantora, Gastona Julie i Felixa Kleina. Svi
oni su djelovali krajem 19. st. i početkom 20. st. i proučavali su te fascinantne tvorevine
dobivane iteracijama, no međutim bez računala, pa nisu mogli uočiti sav njihov značaj.
Prvi puta se termin „fraktal“ pojavljuje 1975. god. kojeg je upotrijebio matematičar
Benoit Mandelbrot, a fraktalna umjetnost se počinje razvijati tek sredinom 1980-ih godina.
Prva fraktalna slika je nastala na naslovnoj stranici časopisa „Scientific American“ 1985. god.
i prikazivala je Mandelbrotov skup.
3
Slika 1 - Scientific American - Mandelbrotov skup [Shane Bow The Chaos of
Mandelbrot, dostupno na: http://shanebow.com/projects/mandelbrot/, učitano:
17.01.2015.]
Takva slika je nastala s intencijom da ponudi vizualne i umjetničke kvalitete. Nedugo
nakon toga izdana je bogato ilustrirana knjiga „The Beauty of Fractals“ čiji su autori Heinz-
Otto Peitgen i Peter Richter. U toj knjizi velik broj ilustracija se temelji na drugom
najpopularnijem fraktalu, a riječ je Juliaovu skupu. [Fraktali i umjetnost, Vesna Mišljenović,
Zagreb (2011./2012. br. 80), str. 223.]
Kako smo konstatirali da je fraktalna umjetnost vrlo mlada, ona nije još pronašla svoje
pravo mjesto u „mainstream“ umjetničkim krugovima, a isto tako nije zastupljena na tržištu
umjetnosti i galerijama. Međutim možemo reći da fraktalna umjetnost ima široku primjenu u
računalnoj animaciji, konkretno u simulaciji rasta biljaka ili primjerice generiranju krajolika.
4
3.Definicija fraktala
Fraktali su slike nastale uzastopnim ponavljanjem neke matematičke funkcije,
odnosno ponavljanjem određenog geometrijskog postupka. Mogli bismo reći da su to zapravo
objekti koji daju jednaku razinu detalja neovisno o razlučivosti koju koristimo.
Kako smo na laboratorijskim vježbama mogli vidjeti kod profesora Horvata, fraktale
je moguće uvećavati beskonačno mnogo puta, a pri tome se prilikom svakog novog uvećanja
mogu opaziti detalji koji prije povećanja nisu bili vidljivi, a da količina novih, možemo reći i
sitnijih detalja uvijek bude otprilike jednaka.
U uvodu je važno za napomenuti da fraktali imaju svoja osnovna svojstva, a to su: [Uvod u
matematičke metode u inženjerstvu, Fraktali, dostupno na:
http://matematika.fkit.hr/novo/izborni/referati/dobrinic_joskic_brdar_fraktali.pdf, 3.
str. učitano: 17.01.2015.]
1) Samo-sličnost – svojstvo objekta da sliči sam na sebe, neovisno o tome koji dio
promatramo i koliko ga puta uvećavamo.
2) Fraktalna dimenzija – vrijednost koja nam daje uvid u to kojoj mjeri pojedini fraktal
ispunjava prostor u kojem se nalazi. Za razliku od fraktalne dimenzije, euklidska
dimenzija koristi se kako bi se izrazila linija (jedna dimenzija), površina (dvije
dimenzije) i prostor (tri dimenzije), te može biti bilo koji prirodni broj ili nula (0, 1, 2,
3, 5, 10, 100, ... ). Fraktalna dimenzija, nasuprot tome koristi se kako bi se postigla
gustoća kojom objekt ispunjava prostor, tj. koliko se novih dijelova pojavljuje pri
uvećavanju rezolucije. Fraktalna dimenzija nije cijeli broj i u pravilu je veća od
euklidke dimenzije.
Primjer:
Fraktalna dimenzija zapadne obale Engleske je 1,3 dok je od Norveške obale 1,52.
One su veće od 1, na temelju čega možemo zaključiti da su euklidske obale shvaćene
kao krivulje. Isto tako to bi značilo da Norveška ima razvodnjeniju obalu od Engleske.
Samo bi približno mogli na eksperimentalnoj razini govoriti o fraktalnim dimenzijama
obale.
Izraz po kojem se mjeri dimenzija je:
d=log(n)/log(s),
a pri tome je:
o d – fraktalna dimenzija
5
o n – broj novih kopija objekta promatrano nakon uvećanja
o s – faktor uvećanja.
Primjer:
Cantorov skup C3 ima dim C3 = log2/log3 = 0.63..... < 1;
Kochova krivulja KK ima dim KK = log4/log3 = 1.2618..... > 1.
3) Oblikovanje iteracijom – svojstvo da se objekt generira nekim matematičkim ili
geometrijskim postupkom, tako da se u osnovni (početni) objekt iterativno ugrađuju
svojstva generatora.
3.1.Podjela fraktala
Fraktale dijelimo prema:
1) stupnju samosličnosti
2) načinu nastanka.
3.1.1.Podjela fraktala prema stupnju samosličnosti
Kod podjele fraktala prema stupnju samosličnosti možemo razlikovati:
1) potpuno samoslične fraktale
2) kvazi samoslične fraktale
3) statičke samoslične fraktale
Potpuno samoslični fraktali sadrže kopije sebe koje su slične cijelom fraktalu. Ovdje je vrlo
bitno poznavati bazu i motiv. Baza je bilo koji oblik koji je sastavljen od linijskih segmenata,
dok je motiv neki drugi oblik koji se također sastoji od linija. Ako se svaka linija baze
nadomjesti oblikom motiva i taj proces nastavi u beskonačnost, dobivamo fraktal.
6
Slika 2 - Baze i motivi [Uvod u fraktale, M.Paušić, dostupno na:
http://www.fer.unizg.hr/_download/repository/Uvod%20U%20Fraktale%20by%20Mla
den%20Pausic.pdf, učitano: 17.01.2015.]
Potpuno samoslični fraktali su svi geometrijski fraktali, a primjere za to možemo vidjeti na
slikama ispod:
slika 2 – Kochova krivulja
slika 4 - Sierpinskijev trokut
slika 5 – Hilbertova krivulja
slika 6 – Cantorov skup
7
Slika 3 - Kochova krivulja [Hrvatski matematički elektronski časopis math.e, Galerija
fraktala, V. Antočić, A. Galinović, dostupno na:
http://e.math.hr/galerija/galerija_print.html, učitano: 17.01.2015.]
Kochovu krivulju uveo je švedski matematičar Helge von Koch. Fraktalna dimenzija
Kochove krivulje je log4 / log3 = 1,2619.
Slika 4 - Nastanak Kochove pahuljice (2D) [Hrvatski matematički elektronski časopis
math.e, Galerija fraktala, V. Antočić, A. Galinović, dostupno na:
http://e.math.hr/galerija/galerija_print.html, učitano: 17.01.2015.]
8
Napomena: razlika između Kochove krivulje i Kochove pahuljice je u tome što krivulja
počinje dužinom, a pahuljica jednakostraničnim trokutom.
Kochovu pahuljicu ćemo kasnije prikazati u praktičnom primjeru: OpenGL ES 2.0 & 3.0 na
Androidu - 3D fraktali (primjer Kochove pahuljice).
Slika 5 - Sierpinskijev trokut - kontrukcija otkidanjem trokuta [Hrvatski matematički
elektronski časopis math.e, Galerija fraktala, V. Antočić, A. Galinović, dostupno na:
http://e.math.hr/galerija/galerija_print.html, učitano: 17.01.2015.]
Sierpinskijev trokut uveo je poljski matematičar Waclaw Sierpinski. Fraktalna dimenzija
Sierpinskijevog trokuta iznosi log3 / log4 = 1,584962.
Poslije većeg broja iteracija možemo opaziti da duljina Kochove krivulje teži u beskonačnost
kada i broj iteracija teži u beskonačnost. Ali cijela ta duljina je i dalje na istoj površini, samo
možemo reći da je malo više zgužvana. Stupanj te zgužvanosti možemo vidjeti iz fraktalne
dimenzije. To nam daje uvid u to u kojoj mjeri nekakav fraktal zauzima ravninu ili općenito
n-dimenzionalni prostor u kojem se nalazi. Tako primjerice Kochova krivulja ima fraktalnu
dimenziju 1,2619, dok Sierpinskijev trokut približno 1,584962. Iz vrijednosti, kao i sa
prethodnih slika, možemo uočiti da je trokut malo gušći od Kochove krivulje, tj. kažemo da
ispunjava veći dio ravnine.
9
Slika 6 - Hilbertova krivulja [Wikipedia, Hilbertova krivulja, dostupno na:
http://hr.wikipedia.org/wiki/Hilbertova_krivulja, učitano: 17.01.2015.]
Hilbertova krivulja je beskonačno gusta krivulja koju je opisao njemački matematičar
David Hilbert 1891. god. Ona nastaje nakon beskonačno mnogo iteracija.
Slika 7 - Contorov skup [Hrvatski matematički elektronski časopis math.e, Galerija
fraktala, V. Antočić, A. Galinović, dostupno na:
http://e.math.hr/galerija/galerija_print.html, učitano: 17.01.2015.]
Za fraktalne skupove moguće je definirati njihove fraktalne dimenzije na nekoliko načina.
Pokazuje se da je fraktalna dimenzija Cantorova skupa strogo manja od 1 i to točno jednaka
log2 / log3 = 0,6309.
Kvazi samoslični fraktali su oni fraktali koji sadrže male kopije sebe koje nisu slične cijelom
fraktalu, već se pojavljuju u iskrivljenom obliku, a primjere za to možemo vidjeti na donjim
slikama:
slika 7 – Juliaov skup
slika 8 – Mandelbrotov skup
10
Slika 8 - Juliaov skup za c = -1 [Hrvatski matematički elektronski časopis math.e,
Galerija fraktala, V. Antočić, A. Galinović, dostupno na:
http://e.math.hr/galerija/galerija_print.html, učitano: 17.01.2015.]
Slika 9 - Mandelbrotov skup [Hrvatski matematički elektronski časopis math.e, Galerija
fraktala, V. Antočić, A. Galinović, dostupno na:
http://e.math.hr/galerija/galerija_print.html, učitano: 17.01.2015.]
Statistički samoslični fraktali su fraktali koji ne sadrže kopije samoga sebe, no međutim
neke njegove osobine kao što je fraktalna dimenzija ostaju iste pri različitim mjerilima.
Primjer za to možemo vidjeti na slici 10.
11
Slika 10 – Dvodimenzionalni Perlinov šum – svjetlije nijanse predstavljaju više
vrijednosti funkcije [Fractal Noise, Neil Blevins, dostupno na:
http://www.neilblevins.com/cg_education/fractal_noise/fractal_noise.html, učitano:
17.01.2015.]
3.1.2.Podjela fraktala prema načinu nastanka
Kod podjele fraktala prema načinu nastanka razlikujemo:
iterativne fraktale
rekurzivne fraktale
slučajne fraktale
Iterativni fraktali nastaju kopiranjem, te rotiranjem i/ili translatiranjem kopije, te mogućim
zamjenjivanjem nekog elementa kopijom (npr. Kochova krivulja).
Rekurzivni fraktali su određeni rekurzivnom matematičkom formulom koja određuje
pripada li određena točka prostora (npr. kompleksna ravnina) skupu ili ne.
Slučajni fraktali posjeduju najmanji stupanj samosličnosti i možemo ih zapaziti najčešće u
prirodi kao što su munje, oblaci, obale ili drveće.
12
Slika 11 - Istra i mnogi drugi poluotoci su fraktali [Neverinov blog, dostupno na:
http://blog.dnevnik.hr/blogodneverina/2010/02/1627237517/fasciniranost-
fraktalima.html, učitano: 17.01.2015.]
Slika 12 - Drvo iz prirode – fraktal [Silvergreen, Deviant art, dostupno na:
http://silvergreen.deviantart.com/art/Fractal-Tree-1646228, učitano: 17.01.2015.]
3.2.Primjena fraktala
Najjednostavniji primjer gdje se susrećemo s konkretnom primjenom fraktala u
računalnoj grafici je crtanje terena, a posebice se to odnosi na planine. Njih možemo crtati
tako da se horizontalno položenom trokutu svaki vrh snizi ili povisi za neku slučajno
odabranu vrijednost. Takvom trokutu se zatim spoje polovišta stranica, te se na taj način
dobivaju četiri nova trokuta. Srednjemu od njih snizimo ili povisimo vrhove kao i prvotnom
trokutu, no međutim tada koristimo dvostruko manje vrijednosti. Isti postupak se nadalje
13
ponavlja za sva četiri trokuta ispočetka. [Uvod u matematičke metode u inženjerstvu, Fraktali,
dostupno na:
http://matematika.fkit.hr/novo/izborni/referati/dobrinic_joskic_brdar_fraktali.pdf, 5.str.
učitano: 17.01.2015.]
Na sljedećoj slici dolje možemo vidjeti funkciju prikazanu u trodimenzionalnom prostoru.
Ovdje su više vrijednosti jednostavno prikazane na višem položaju. Tako se dobiva model
koji uvelike nalikuje planini.
Slika 13 - Stvorena planina uz pomoć Perlinovog šuma (WebGL Demo – Fractal Terrain
Generator, dostupno na: http://www.webgl.com/2012/05/webgl-demo-fractal-terrain-
generator/ , učitano: 17.01.2015.]
Ako bi uzeli u obzir sustave iteriranih funkcija u tri dimenzije, mogli bismo iscrtavati razne
objekte kao što su drveće, cvijeće, grmlje, korijenje i tome slično. Ako to isto napravimo u
trodimenzionalnom sustavu i na kraj svake grančice dodamo pokoji list, rezultat bi bio
nevjerovatno sličan stvarnim pojavama u prirodi, baš kao što je prikazano na slici 14. Od
manje bitnijih primjena tu je predviđanje stohastičkih procesa kao što su recimo potresi,
slaganje snopova optičkih vlakana, oponašanje rada neuronskih mreža za razvoj umjetne
inteligencije i dr. Za uređaje kao što su mobiteli, proizvode se antene u obliku fraktala koje
zbog toga koriste široki spektar frekvencija, a uz to ne zauzimaju puno prostora.
14
Slika 14 - Trodimenzionalni fraktal – drvo [Pythagoras Tree, dostupno na:
http://www.phidelity.com/blog/phidelity/blog/fractal/pythagoras-tree/, učitano:
17.01.2015.]
3.3.Fraktalna dimenzija
Fraktalna dimenzija je vrijednost koja nam daje uvid u to u kojoj mjeri nekakav
fraktal ispunjava prostor u kojem se nalazi. Pronašli smo podosta definicija fraktalnih
dimenzija od kojih se niti jedna nije pokazala univerzalnom. Najbolja je dimenzija
samosličnosti, no međutim nju upotrebljavamo samo kod jako jednostavnih geometrijskih
fraktala. Za teoriju nam je najbitnija ona Hausdorffova dimenzija, a u konkretnim
slučajevima, odn. u praksi najviše se koristi Minkowski-Bouligandova dimenzija. [Uvod u
matematičke metode u inženjerstvu, Fraktali, dostupno na:
http://matematika.fkit.hr/novo/izborni/referati/dobrinic_joskic_brdar_fraktali.pdf, 6. str.
učitano: 17.01.2015.]
Dimenzija samosličnosti koristi razne promjene mjera (primjerice dužine, površine,
obujmi, ...) u odnosu na mijenjanje broja iteracija kod potpuno samosličnih fraktala. Kod
Kochove krivulje svaka naredna iteracija daje četiri puta više segmenata na tri puta manje
dužine. Ako bismo broj segmenata označili sa N, a dužinu segmenta s L, ukupno bi dobili
dužinu krivulje NL. Možemo zatim reći da za Kochovu krivulju vrijedi: 4𝑁 (𝐿
3) = 𝑁𝐿𝑑 ako za
mjeru dužine uvrstimo spomenuti „d-dimenzionalni metar“. Daljnjim preuređivanjem
15
jednadžbe dobivamo 𝑑 = 𝑙𝑜𝑔34 ili češće 𝑑 =𝑙𝑜𝑔4
𝑙𝑜𝑔3. Tako bi mjerna jedinica za Kochovu
krivulju bila otprilike m1.2619
. Općenito možemo reći da se dimenzija potpuno samosličnog
fraktala računa po formuli 𝑑 =𝑙𝑜𝑔𝑁
𝑙𝑜𝑔𝐿.
Minkowski-Bouligandova dimenzija – ako bismo uzeli fraktal koji leži u ravnini i prekrili
ga proizvoljnim brojem N sukladnih kvadrata duljine stranice A, smanjivanjem te duljine
kvadrata (a samim time i povećanjem njihovog broja) promijenio bi se i broj kvadrata koji
sadrže fraktal. Upravo ova metoda koristi odnos broja tih kvadrata i duljine stranica. Na taj
način možemo odrediti dimenziju jednostavnih objekata, čija nam je dimenzija već poznata
(razne definicije dimenzije ne bi trebale davati različite rezultate kod vrlo jednostavnih
objekata) kao što su primjerice kvadrati. Dobit ćemo opću formulu za kvadrat (pri tome
znamo da se radi o dvodimenzionalnom kvadratu): 𝑁 =1
𝐴2. Ako bismo učinili istu stvar i sa
dužinom (jednodimenzionalnom), te kockom (trodimenzionalnom), dobili bi opće formule:
𝑁 =1
𝐴 i 𝑁 =
1
𝐴3 . Iz ovih primjera vidimo opću formulu za objekte bilo koje dimenzije
𝑁 =1
𝐴𝑑, tj. 𝑑 =
𝑙𝑜𝑔𝑀
𝑙𝑜𝑔1
𝐴
. Valja istaknuti da ova metoda ne daje uvijek potuno točne rezultate, te
da joj se rezultati pomiču stvarnima s povećanjem broja dužina, kvadrata i kocaka. Najviše se
koristi kod određivanja fraktalne dimenzije nepravilnih objekata. [Uvod u matematičke
metode u inženjerstvu, Fraktali, dostupno na:
http://matematika.fkit.hr/novo/izborni/referati/dobrinic_joskic_brdar_fraktali.pdf, 7. str.
učitano: 17.01.2015.]
Topološka dimenzija je ono što nazivamo još i intuitivnom dimenzijom, tj. broj smjerova u
kojima bismo mogli ići da smo u određenom objektu, odnosno broj stupnjeva slobode. Na
takav način je svaka linija (ravna ili zakrivljena) jednodimenzionalna, jer postoji samo jedan
stupanj slobode, a to je dužina (lijevo-desno). Svaka je ploha (ravna ili savinuta)
dvodimenzionalna, jer postoje dva stupnja slobode – dužina i širina (lijevo-desno i gore-
dolje). Topološka dimenzija uvijek je pozitivan cijeli broj ili nula. Ako bi to sagledavali
stručnije, topološka dimenzija se može definirati i kao najmanja moguća vrijednost n, tako da
se bilo koji otvoreni pokrivač (pokrivač čiji su svi elementi otvoreni skupovi) može podesiti
tako da svaka točka bude najviše n+1 element. Primjerice, ako želimo odrediti topološku
dimenziju kružnice, konstruirat ćemo joj pokrivač od otvorenih kružnih lukova. Zatim ćemo
podesiti taj pokrivač tako da smanjimo preklapanje njegovih elemenata na najmanju moguću
mjeru, ali da cijela kružnica i dalje bude potpuno pokrivena. Pošto smo uzimali otvorene
lukove, preklapanje je neizbježno, a može se napraviti tako da svaka točka kružnice bude dio
16
samo jednog ili dva elementa pokrivača. Najveća je vrijednost n = 2, tako da topološka
dmenzija iznosi n – 1, te zaključujemo na temelju toga da je kružnica jednodimenzionalna.
Ovo matematičko objašnjenje se na prvi pogled možda čini nepotrebnim, ali je vrlo bitno u
nekim elementima više matematike, kao primjerice u našoj seminarkoj temi o fraktalima.
[Uvod u matematičke metode u inženjerstvu, Fraktali, dostupno na:
http://matematika.fkit.hr/novo/izborni/referati/dobrinic_joskic_brdar_fraktali.pdf, 8. str.
učitano:17.01.2015.]
17
4.Prikaz grafike s OpenGL ES
Android okvir pruža mnogo standardnih alata za stvaranje funkcionalnog grafičkog
sučelja. Ako primjerice želimo postići veću kontrolu nad onime što želimo prikazati na
zaslonu kao što je modeliranje u trodimenzionalnim slikama trebali bismo koristiti više vrsta
različitih funkcija. OpenGL ES API od strane Android okvira nudi čitav niz alata za prikaz
vrhunske animirane grafike koje su ograničene samo našom maštom i također možemo imati
koristi od ubrzanja grafičke obrade jedinica (GPU) koje se nalaze na mnogim Android
uređajima.
4.1.Izgradnja OpenGL ES okruženja
Kako bi mogli iscrtavati grafičke objekte uz pomoć OpenGL ES na našem Android-u
moramo prvo kreirati određene poglede na spremnike za njih. Jedan od najboljih načina za to
je implementacija sučelja GLSurfaceView i GLSurfaceView.Renderer. GLSurfaceView je
spremnik za grafičko crtanje s OpenGL-om i GLSurfaceView-om. Renderer kontrolira ono
što je nacrtano u tom pogledu. GLSurfaceView je samo jedan od načina da se u OpenGL ES
uključi grafika u takav program. Primjerice za prikaz punog zaslona to je definitivno najbolji
izbor.
4.1.1.Deklariranje OpenGL koristeći Manifest
Kako bi mogli koristiti OpenGL ES 2.0 API u našoj aplikaciji moramo ga deklarirati u
našem manifestu sa ovim XML isječkom:
<uses-feature android:glEsVersion="0x00020000"
android:required="true" />
Ako naša aplikacija koristi kompresiju teksture, također moramo deklarirati u manifestu koje
formate kompresije naša aplikacija podržava. To vrijedi samo za kompatibilne uređaje.
[Developers, Displaying Graphics with OpenGL ES, dostupno na:
http://developer.android.com/training/graphics/opengl/environment.html, 25.01.2015.]
18
<supports-gl-texture
android:name="GL_OES_compressed_ETC1_RGB8_texture" />
<supports-gl-texture
android:name="GL_OES_compressed_paletted_texture" />
4.1.2.Kreiranje aktivnosti za OpenGL ES grafiku
Android aplikacije koje koriste OpenGL ES imaju aktivnosti baš kao i bilo koje druge
aplikacije koja ima korisničko sučelje. Glavna razlika od drugih aplikacija je ono što se stavi
u raspored za naše aktivnosti. Dok se u mnogim aplikacijama koriste TextView, gumb i
ListView, u aplikaciji koji koristi OpenGL ES, također možete dodati i GLSurfaceView.
Sljedeći kod pokazuje minimalnu provedbu aktivnosti koje koristi GLSurfaceView kao svoj
primarni pogled [Developers, Displaying Graphics with OpenGL ES, dostupno na:
http://developer.android.com/training/graphics/opengl/environment.html, 25.01.2015.]:
public class OpenGLES20Activity extends Activity {
private GLSurfaceView mGLView;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Create a GLSurfaceView instance and set it
// as the ContentView for this Activity.
mGLView = new MyGLSurfaceView(this);
setContentView(mGLView);
}
}
4.1.3.Gradnja GLSSurfaceView objekata
GLSurfaceView je specijalizirani pogled u kojem možemo crtati grafiku OpenGL ES.
To samo za sebe ne znači baš mnogo. Stvarni crtež objekata se kontrolira u
GLSurfaceView.Renderer-u koje smo postavili na ovom prikazu. Naime, kod za ovaj objekt
je tako malen, pa možemo biti u iskušenju da ga preskočimo ili stvorimo nemodificiranu
GLSurfaceView instancu. Morali bismo proširiti ovu klasu kako bi se omogućilo snimanje
događaja. Veoma važan programski kod za GLSurfaceView je minimalan, tako da za brzu
19
provedbu, uobičajeno je da samo stvorimo unutarnje klase u aktivnosti koje koristimo
[Developers, Displaying Graphics with OpenGL ES, dostupno na:
http://developer.android.com/training/graphics/opengl/environment.html, 25.01.2015.]:
class MyGLSurfaceView extends GLSurfaceView {
public MyGLSurfaceView(Context context){
super(context);
// Set the Renderer for drawing on the GLSurfaceView
setRenderer(new MyRenderer());
}
}
Kada koristimo OpenGL ES 2.0, moramo dodati još jedan poziv na svoj GLSurfaceView
konstruktor, te naznačimo da želimo koristiti 2.0 API [Developers, Displaying Graphics with
OpenGL ES, dostupno na:
http://developer.android.com/training/graphics/opengl/environment.html, 25.01.2015.]:
// Create an OpenGL ES 2.0 context
setEGLContextClientVersion(2);
Jedan drugi izborni dodatak našem GLSurfaceView-u je postavljanje načina za pogled kada je
došlo do promjene crtanja podataka pomoću
GLSurfaceView.RENDERMODE_WHEN_DIRTY postavke [Developers, Displaying
Graphics with OpenGL ES, dostupno na:
http://developer.android.com/training/graphics/opengl/environment.html, 25.01.2015.]:
// Render the view only when there is a change in the drawing data
setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
Ova postavka sprječava GLSurfaceView okvir od toga da ponovno iscrtava dok ne pozovemo
funkciju requestRender(), što je učinkovitije za ovaj uzorak.
20
4.1.4.Gradnja Renderer klase (klasa prikazivanja)
Implementacija GLSurfaceView.Renderer klase unutar aplikacije koja koristi OpenGL ES je
dio gdje stvari počinju biti zanimljive i interesantne. Ova klasa kontrolira ono što je iscrtano u
GLSurfaceView s kojim je i povezana. Postoje tri metode u renderer klasi koje se pozivaju od
strane Android sustava kako bi shvatili što i kako se iscrtava na GLSurfaceView-u:
onSurfaceCreated() – poziva se samo jednom kako bi se postavili pogledi OpenGL ES
okruženja;
onDrawFrame() – pozivanje prilikom svakog prikaza iscrtavanja;
onSurfaceChanged() – poziva se prilikom promjene geometrijskog prikaza, primjerice
izmijene orijentacije ekrana uređaja.
Primjer koda ispod je osnovna provedba OenGL ES prikazivača koji ne radi ništa bitno, samo
postavlja sivu pozadinu u GLSurfaceView-u [Developers, Displaying Graphics with OpenGL
ES, dostupno na: http://developer.android.com/training/graphics/opengl/environment.html,
25.01.2015.]:
public class MyGLRenderer implements GLSurfaceView.Renderer {
public void onSurfaceCreated(GL10 unused, EGLConfig config) {
// Set the background frame color
GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
}
public void onDrawFrame(GL10 unused) {
// Redraw background color
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
}
public void onSurfaceChanged(GL10 unused, int width, int height)
{
GLES20.glViewport(0, 0, width, height);
}
}
Kod koji smo naveli iznad je u biti jednostavna mala Android aplikacija koja prikazuje sivi
zaslon pomoću OpenGL-a. Ova klasa je temelj koji je potreban za početak iscrtavanja
21
grafičkih elemenata s OpenGL-om. Sada kada smo upoznati s OpenGL ES API-jem, možemo
postaviti OpenGL ES okruženje u aplikaciji i početi crtati grafiku.
4.2.Definiranje oblika
Biti u stanju definirati oblike koji se mogu izvesti u kontekstu pogleda OpenGL ES-a
je prvi korak u stvaranju visokozahtjevne grafike. Crtanje s OpenGL ES-om može biti malo
teže bez poznavanja nekoliko osnovnih stvari o tome kako OpenGL ES očekuje definiranje
grafičkih objekata. Ovdje ćemo objasniti kako je OpenGL ES koordinatni sustav relativan u
odnosu na Android-ov zaslon uređaja, osnove definiranja oblika, oblik lica, te definiranje
trokuta i kvadrata.
4.2.1.Primjer definiranja trokuta
OpenGL ES omogućuje definiranje crtanja objekata pomoću koordinata u
trodimenzionalnom prostoru. Prije nego što nacrtamo trokut, moramo definirati svoje
koordinate. U OpenGL, tipičan način da to učinimo je da si definiramo najvišu točku ili tjeme
i brojeve s pomičnim zarezom za koordinate. Za maksimalnu učinkovitost, pišemo ove
koordinate u ByteBuffer, koji je uspješno prošao u OpenGL ES grafički cjevovod za obradu.
[Developers , Defining Shapes, dostupno na:
http://developer.android.com/training/graphics/opengl/environment.html, 25.01.2015.]
public class Triangle {
private FloatBuffer vertexBuffer;
// number of coordinates per vertex in this array
static final int COORDS_PER_VERTEX = 3;
static float triangleCoords[] = { // in counterclockwise
order:
0.0f, 0.622008459f, 0.0f, // top
-0.5f, -0.311004243f, 0.0f, // bottom left
0.5f, -0.311004243f, 0.0f // bottom right
};
// Set color with red, green, blue and alpha (opacity) values
22
float color[] = { 0.63671875f, 0.76953125f, 0.22265625f, 1.0f };
public Triangle() {
// initialize vertex byte buffer for shape coordinates
ByteBuffer bb = ByteBuffer.allocateDirect(
// (number of coordinate values * 4 bytes per float)
triangleCoords.length * 4);
// use the device hardware's native byte order
bb.order(ByteOrder.nativeOrder());
// create a floating point buffer from the ByteBuffer
vertexBuffer = bb.asFloatBuffer();
// add the coordinates to the FloatBuffer
vertexBuffer.put(triangleCoords);
// set the buffer to read the first coordinate
vertexBuffer.position(0);
}
}
Po početnim vrijednostima, OpenGL ES pretpostavlja koordinatni sustav [0,0,0] (X, Y, Z)
i specificira središte GLSurfaceView okvir. [1,1,0] je gornji desni kut okvira i [- 1, -1,0] je u
donjem lijevom kutu okvira.
4.2.2.Primjer definiranja kvadrata
Definiranje trokuta je prilično lako u OpenGL, ali što ako želimo da nešto malo
složenije? U ovom primjeru konkretno mislimo na kvadrat. Postoji nekoliko načina za
iscrtavanje kvadrata, ali tipičan način izrade takvog oblika u OpenGL ES-u je koristiti dva
trokuta nacrtana zajedno kao što je prikazano na slici ispod.
23
Slika 15 - Crtanje kvadrata uz pomć 2 trokuta [Defining Shapes, dostupno na:
http://developer.android.com/training/graphics/opengl/shapes.html, učitano:
25.01.2015.]
Opet bi trebali definirati točke u suprotnom smjeru od kazaljke na satu kako bi oba trokuta
predstavljali ovaj oblik, te postaviti vrijednosti u ByteBuffer. Kako bi se izbjeglo da dvije
koordinate dijele svaki trokut dva puta, koristimo se popisom za crtanje koji daje upute
OpenGL ES-u na način kako da grafički cjevovod izvuće te vrhove. Pogledajmo kod za
kvadrat [Developers, Defining Shapes, dostupno na:
http://developer.android.com/training/graphics/opengl/environment.html, 25.01.2015.]:
public class Square {
private FloatBuffer vertexBuffer;
private ShortBuffer drawListBuffer;
// number of coordinates per vertex in this array
static final int COORDS_PER_VERTEX = 3;
static float squareCoords[] = {
-0.5f, 0.5f, 0.0f, // top left
-0.5f, -0.5f, 0.0f, // bottom left
0.5f, -0.5f, 0.0f, // bottom right
0.5f, 0.5f, 0.0f }; // top right
private short drawOrder[] = { 0, 1, 2, 0, 2, 3 }; // order to
draw vertices
public Square() {
// initialize vertex byte buffer for shape coordinates
24
ByteBuffer bb = ByteBuffer.allocateDirect(
// (# of coordinate values * 4 bytes per float)
squareCoords.length * 4);
bb.order(ByteOrder.nativeOrder());
vertexBuffer = bb.asFloatBuffer();
vertexBuffer.put(squareCoords);
vertexBuffer.position(0);
// initialize byte buffer for the draw list
ByteBuffer dlb = ByteBuffer.allocateDirect(
// (# of coordinate values * 2 bytes per short)
drawOrder.length * 2);
dlb.order(ByteOrder.nativeOrder());
drawListBuffer = dlb.asShortBuffer();
drawListBuffer.put(drawOrder);
drawListBuffer.position(0);
}
}
Ovaj primjer daje nam ono što je potrebno za stvaranje složenijih oblika s OpenGL-om.
Općenito, koristimo zbirke trokuta za crtanje objekata.
4.3.Crtanje oblika
Nakon što smo prikazali oblike koji se mogu izvesti s OpenGL, poželjet ćemo ih i
iscrtati. Crtanje oblika s OpenGL ES 2.0 traje malo više koda, jer API omogućuje veliku
kontrolu nad slikama koji pruža cjevovod.
4.3.1.Inicijalizacija oblika Prije nego bilo što nacrtamo, moramo inicijalizirati i učitati oblike koje namjeravamo nacrtati.
Osim ako strukturu (izvornih koordinata) oblika koje koristimo u svom programu promjenimo
tijekom izvršenja, trebali bismo ih inicijalizirati u onSurfaceCreated() metodi našeg renderer-a
(prikazivača) za pamćenje i učinkovitost obrade. [Developers, Drawing Shapes, dostupno na:
http://developer.android.com/training/graphics/opengl/environment.html, 25.01.2015.]:
25
public void onSurfaceCreated(GL10 unused, EGLConfig config) {
...
// initialize a triangle
mTriangle = new Triangle();
// initialize a square
mSquare = new Square();
}
4.3.2.Crtanje oblika
Crtanjem definiramo oblik pomoću OpenGL ES-a 2.0 i to zahtijeva značajnu količinu
koda, jer moramo pružiti puno detalja u grafici pruzujući sve kroz cjevovod. Moramo
definirati sljedeće:
Vertex Shader - OpenGL ES kod za grafiku za prikaz vrhova oblika;
Fragment Shader - OpenGL ES kod za prikazivanje oblika s bojama ili teksturama.
Program - OpenGL ES objekt koji sadrži sjenčanje koje ćemo koristiti za izradu
jednog ili više oblika.
Shader je računalni program koji se koristi za napraviti sjenčanje.
Trebamo barem jedan vrh osjenčati kako bi nacrtali oblik i jedan fragment osjenčati bojom da
bi prikazali oblik. To sjenčanje mora biti iskompajlirano, a zatim je dodano u OpenGL ES
program, koji se potom koristi za iscrtavanje oblika. Ovdje je primjer kako definirati osnovno
sjenčanje koje možemo koristiti za crtanje oblika [Developers, Drawing Shapes, dostupno na:
http://developer.android.com/training/graphics/opengl/environment.html, 25.01.2015.].
private final String vertexShaderCode =
"attribute vec4 vPosition;" +
"void main() {" +
" gl_Position = vPosition;" +
"}";
private final String fragmentShaderCode =
"precision mediump float;" +
"uniform vec4 vColor;" +
"void main() {" +
26
" gl_FragColor = vColor;" +
"}";
Shaderi ili zasjenjivači sadrže OpenGL sjenčanje jezika (GLSL) kod kojeg se mora
iskompajlirati prije upotrebe u OpenGL ES okruženju. Kako bi mogli nacrtati svoje oblike,
moramo prvo sastaviti Shader šifru, dodati ga u OpenGL ES programski objekt, a zatim
povezati program. To možemo napraviti u našem nacrtanom objektu konstruktora, pa je to
dovoljno učiniti samo jednom.
Kompajliranje OpenGL ES shadera i povezivanja programa je skuplji u odnosu na
CPU ciklus i vrijeme obrade, tako da treba izbjegavati to više puta. Ako ne znamo sadržaj
naših shader-a ili zasjenjivača tijekom instalacije, trebali bismo napraviti svoj kod, dovoljno
ga je samo jednom kreirati i spremiti za kasniju uporabu [Developers, Drawing Shapes,
dostupno na: http://developer.android.com/training/graphics/opengl/environment.html,
25.01.2015.].
public class Triangle() {
...
int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER,
vertexShaderCode);
int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER,
fragmentShaderCode);
mProgram = GLES20.glCreateProgram(); // create empty
OpenGL ES Program
GLES20.glAttachShader(mProgram, vertexShader); // add the
vertex shader to program
GLES20.glAttachShader(mProgram, fragmentShader); // add the
fragment shader to program
GLES20.glLinkProgram(mProgram); // creates
OpenGL ES program executables
}
4.4.Primjena projekcije i pogled kamere
27
U OpenGL ES okruženju, projekcije i pogled kamere omogućuju prikazivanje
nacrtanih objekata na način da više fizički sliče kao oni iz stvarnosti. Ova simulacija fizičkog
pogleda je načinjena s matematičkim transformacijama nacrtanih objekata uz pomoć
koordinata:
Projekcija - ova transformacija postavlja koordinate nacrtanih objekata na temelju
širine i visine GLSurfaceView gdje se prikazuju.
Pogled kamere - ova transformacija podešava koordinate nacrtanih objekata na
temelju virtualnog položaja kamere.
4.4.1. Definiranje projekcije
Podaci za transformaciju projekcijom se izračunavaju onSurfaceChanged() metodom
naše GLSurfaceView.Renderer klase. Sljedećim kodom uzimamo visinu i širinu
GLSurfaceView i koristimo ga za popunjavanje matrice projekcije transformacije pomoću
Matrix.frustumM () metode [Developers, Applying Projection and Camera Views, dostupno
na: http://developer.android.com/training/graphics/opengl/environment.html, 25.01.2015.]:
@Override
public void onSurfaceChanged(GL10 unused, int width, int height) {
GLES20.glViewport(0, 0, width, height);
float ratio = (float) width / height;
// this projection matrix is applied to object coordinates
// in the onDrawFrame() method
Matrix.frustumM(mProjectionMatrix, 0, -ratio, ratio, -1, 1, 3,
7);
Ovaj kod popunjava matricu projekcija, mProjectionMatrix koje možemo kombinirati s
transformacijom kamera u onDrawFrame() metodi.
4.4.2. Definiranje pogleda kamere
Kompletan proces transformacije nacrtanih objekata završava dodavanjem transformacija u
pogled kamere kao dio procesa crtanja. U sljedećem primjeru koda, transformacija pogleda
kamere se izračunava pomoću Matrix.setLookAtM() metode, a zatim u kombinaciji s
prethodno izračunatom projekcijom matrice [Developers, Applying Projection and Camera
28
Views, dostupno na: http://developer.android.com/training/graphics/opengl/environment.html,
25.01.2015.].
public void draw(float[] mvpMatrix) { // pass in the calculated
transformation matrix
...
// get handle to shape's transformation matrix
mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram,
"uMVPMatrix");
// Pass the projection and view transformation to the shader
GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mvpMatrix,
0);
// Draw the triangle
GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vertexCount);
...
}
4.5. Dodavanje pokreta
Crtanje objekata na zaslonu je temeljna značajka OpenGL, ali možemo to učiniti s drugim
Android grafičkim okvirima klasa, uključujući Canvas i Drawable objekte. OpenGL ES nudi
dodatne mogućnosti za kretanje i pretvaranje nacrtanih objekata u tri dimenzije ili druge
jedinstvene načine za kreiranje korisnikovih iskustava.
4.5.1.Rotiranje oblika
Rotirajunje objekata s OpenGL ES 2.0 je relativno jednostavno. Možemo jednostavno stvoriti
drugu matricu transformacije (matricu rotacije), a zatim je kombinirati sa svojim projekcijama
i pogledom kamere matricom transformacija [Developers, Adding Motion,dostupno na:
http://developer.android.com/training/graphics/opengl/environment.html, 25.01.2015.]:
private float[] mRotationMatrix = new float[16];
public void onDrawFrame(GL10 gl) {
...
float[] scratch = new float[16];
29
// Create a rotation transformation for the triangle
long time = SystemClock.uptimeMillis() % 4000L;
float angle = 0.090f * ((int) time);
Matrix.setRotateM(mRotationMatrix, 0, angle, 0, 0, -1.0f);
// Combine the rotation matrix with the projection and camera
view
// Note that the mMVPMatrix factor *must be first* in order
// for the matrix multiplication product to be correct.
Matrix.multiplyMM(scratch, 0, mMVPMatrix, 0, mRotationMatrix,
0);
// Draw triangle
mTriangle.draw(scratch);
}
4.5.2. Omogućavanje kontinuiranog prikazivanja (renderiranja)
Ako se slučajno naš oblik ne okreće, moramo komentirati u kodu dio s postavkom
GLSurfaceView.RENDERMODE_WHEN_DIRTY. OpenGL inače rotira oblik
inkrementalno i čeka poziv funkcije requestRender() iz GLSurfaceView spremnika
[Developers, Adding Motion, dostupno na:
http://developer.android.com/training/graphics/opengl/environment.html, 25.01.2015.]:
public MyGLSurfaceView(Context context) {
...
// Render the view only when there is a change in the drawing
data.
// To allow the triangle to rotate automatically, this line is
commented out:
//setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
}
Osim ako imamo objekte koji se mijenjaju bez bilo kakve interakcije s korisnikom, onda je
dobra ideja imati ovu zastavicu podignutu ili uključenu.
30
5. Prikaz grafike s OpenGL ES iz Processinga 2.0
Kako Android platforma sadrži potpunu podršku za Java okruženje u prethodnom poglavlju
obradili smo OpenGL ES iz perspektive Jave. No, Android je i ujedno open source ekosustav,
što znači da Java nije jedini alat koji nam stoji za manipulaciju OpenGL ES-a. Na Android
platformi možemo pristupiti OpenGL ES-u iz bilo kojeg skriptnog jezika putem Android
SL4A ili nekog trećeg ekosustava kao što je to Processing 2.0.
Kako bi učinili cijelokupnu stvar nama zanimljivijom, pitali smo se kako upravljati OpenGL
ES-om iz neke druge perspektive koja nije Javina, istraživanjem došli smo do 2 odgovora.
Prvi je, da je to moguće uz pomoć C/C++ jezika kojeg ćemo ugraditi u Java aplikaciju putem
JNI sučelja. Drugi je, putem Processing 2.0 API-a. Naime, Processing je veoma popularan
jezik i okruženje za programiranjem sa velikim naglaskom na računalnu grafiku i grafičke
elemente. Kada smo vidjeli da Processing 2.0 sadrži podršku za Android grafiku putem
OpenGL ES-a odlučili smo dalje istražiti tu perspektivu razvoja.
U ovom poglavlju napraviti ćemo kratak pregled u OpenGL ES iz perspektive Processing 2.0
jezika. U prethodnim poglavljima razmatrali smo kako je OpenGL ES zapravo okvir za koji je
zadužna grafička kartica na uređaju (eng. Graphic Processing Unit, u nastavku GPU). Upravo
taj okvir čini direktan način programiranja 3D grafike na Androidu. OpenGL ES je također
API koji je namjenjen da se koristi na više platformi, a ne samo na Androidu, te ujedno čini i
podskup OpenGL-a. Minimalni hardwerski zahtjevi da pokrenemo neku 3D grafiku na
Androidu iz Processinga su sljedeći:
GPU koji ima podršku minimalno za OpenGL ES 1.1
Android 2.1+, no neka svojstva OpenGL još uvijek nedostaju na Androidu 2.1, tako da
se preporuča upotreba minimalno Android 2.2 platforme
Kada radimo Processing skicu za Android dostupna su nam 2 stroja renderiranja. Prvi je sam
OpenGL ES, dok je drugi Android 3D (u nastavku A3D). Cijelokupan Processing na
Androidu koristi OpenGL ES direktno, i sve skice koje izradimo će u runtime-u koristiti
OpenGL ES 2.0. Stroj renderiranja u Processingu je zapravo modul koji je zadužan za sva
crtanja i sve operacije sa kojima crtamo. Stroj renderiranja specificiramo kada stvaramo
objekt ekrana i zadajemo mu rezoluciju. U slučaju ako ne zadamo neki stroj renderiranja
Processing će upotrebljavati A2D. U nastavku ćemo razmotriti neke od scenarija korištenja
31
Processinga na Androidu te uvidjeti da je zapravo puno intuitivnije za koristiti Processingom
API za crtanje nego čiste pozive OpenGL ES-a iz Jave.
Prije nego se upustimo u naprednije stvari iz Processinga razmotrimo primjer kako crtati na
platno koje nećemo prikazati na ekranu (eng. Offscreen drawing). Da bi izradili platno u
Processingu potrebno je pozvati se na createGraphics() metodu.
PGraphicsAndroid3D pg;
void setup() {
size(480, 800, A3D);
pg = createGraphics(300, 300, A3D);
...
}
Ovakav crtež koji se ne prikazuje na ekranu, kasnije možemo iskoristi kao sliku za teksturu
objekta ili da kombiramo sa drugim slojevima. Naprimjer, ovako:
void draw() {
pg.beginDraw();
pg.rect(100, 100, 50, 40);
pg.endDraw();
...
cube.setTexture(pg.getOffscreenImage());
...
}
5.1. Geometrijske transformacije
Koordinatni sustav u Processingu definiran je sa X osi koja se proteže od lijeve prema desnoj
strani, Y os od doljnoj prema gornjoj strani i negativna Z os pokazuje od ekrana. Kada bi
gledali ishodište koordinatnog sustava ono bi bilo u gornjom lijevom kutu. Ovo je važno da
znamo jer sve geometrijske transformacije koje ćemo primjeniti nad našim objektima će se
32
odnositi na cijeli koordinatni sustav. Iz slike 16. možemo vidjeti kako je koordinatni sustav za
3D implementiran u Processingu.
Slika 16 Koordinatni sustav kako je implementiran u Processingu
5.1.1. Translacija
Translacija se vrši uz pomoć translate(dx, dy, dz) funkcije.
void setup() { size(240, 400, A3D); stroke(255, 150);
} void draw() {
background(0); translate(50, 50, 0); noStroke(); fill(255, 200); rect(60, 0, 100, 100);
}
Iz slike 17. možemo vidjeti kako će gornji kod napraviti translaciju rect-a.
33
Slika 17 Primjer translacije
5.1.2. Rotacija
Rotacija uvijek sadrži jednu od osi oko koje objekt rotira. Ta os može biti koordinatna ili
može biti neki proizvoljni vektor.
rotateX(angle), rotateY(angle), rotateZ(angle), rotate(angle, vx,
vy, vz)
void setup() {
size(240, 400, A3D);
stroke(255, 150);
}
void draw() {
background(0);
34
rotateZ(PI / 4);
noStroke();
fill(255, 200);
rect(60, 0, 100, 100);
}
Iz doljnje slike možemo vidjeti kako gornji isječak koda će rotirati rect.
Slika 18 Prikaz rotacije
35
5.1.3. Skaliranje
Skaliranje može biti uniformno, znači da se objekt proširuje u svim smjerovima za određenu
jednaku duljinu, tj. za neki faktor. Ili možemo definirati funkciji scale(sx, sy, sz) zasebne
vrijednosti za svaki smjer.
void setup() {
size(240, 400, A3D);
stroke(255, 150);
}
void draw() {
background(0);
scale(1.5, 3.0, 1.0);
noStroke();
fill(255, 200);
rect(60, 0, 60, 60);
}
Iz gornjeg isječka, naš pravokutnik će se skalirati kako je prikazano na sljedećoj slici.
36
Slika 19 Primjer skaliranja u Processingu
5.2. Kamera i perspektiva
Konfiguriranje pogleda sceneu A3D zahtjeva konfiguraciju lokaciju kamere i volumena
gledanja. Postavljanje kamere je specificirano pozicijom oka, centrom scene te koja
koordinatna os gleda prema gore. Funkcija za konfiguraciju kamere u Processingu je:
camera(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ);
Ako se gore definirana funkcija ne poziva, A3D automatski će ju pozvati sa defaltnim
vrijednostima koje su:
37
camera(width / 2.0, height / 2.0, (height / 2.0) / tan(PI * 60.0 /
360.0), width / 2.0, height / 2.0, 0, 0, 1, 0);
Razmotrimo sada primjer postavljanja kamere.
void setup() {
size(240, 400, A3D);
fill(204);
}
void draw() {
lights();
background(0);
camera(30.0, mouseY, 220.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
noStroke();
box(90);
stroke(255);
line(-100, 0, 0, 100, 0, 0);
line(0, -100, 0, 0, 100, 0);
line(0, 0, -100, 0, 0, 100);
}
Gornji programski isječak nacrtati će sljedeću grafiku iz koje možemo vidjeti jednostavno
kako smo zapravo postavili kameru u prostor.
38
Slika 20 Primjer kamere u prostoru
Kako bi napravili pogled iz određene perspekitve koristimo funkciju perspecitve. Volumen
pogleda u tom slučaju je smanjena ili povećana piramida te konvergencija nacrtanih linija
prema oku stvara perspektivnu projekciju gdje objekti koji su smješteni dalje će se činiti
manji, dok oni bliže će se činiti većima.
Slika 21 Slika objašnjava elemente koji su uključeni u perspektivnu geometriju
39
5.3. Stvaranje 3D objekata
Processing je veoma jednostavan za korištenje, te stvaranje 3D objekata je puno
jednostavnije, brže i intuitivnije nego je to recimo u Javi. On nam definira u A3D već
određene predefinirane objekte poput sfere i kocke. Kako stvarati 3D objekte je najlakše
objasniti na primjeru. Primjer jednostavnosti upotrebe jednostavnih grafičkih primitiva nalazi
se u nastavku.
void setup() {
size(240, 400, A3D);
stroke(0);
}
void draw() {
background(0);
translate(width/2,height/2,0);
fill(200, 200);
pushMatrix();
rotateY(frameCount*PI/185);
box(150, 150, 150);
popMatrix();
fill(200, 40, 100, 200);
pushMatrix();
rotateX(-frameCount*PI/200);
sphere(50);
popMatrix();
}
Ovaj programski isječak prikazuje nam kako koristiti neke predefinirane grafičke primitive.
Kada ga iskompajliramo i pokrenemo na Android uređaju ili emulatoru, dobiti ćemo prikaz
koji se nalazi na idućoj slici.
40
Slika 22 Primjer korištenja predefiniranih 3d grafičkih primitiva
Drugi način stvaranja 3D objekata koji nisu predefinirani je putem beginShape(), endShape()
konstrukata. Ove dvije funkcije omogućavaju nam da stvorimo složenije objekte tako da
specificiramo vrhove i način njihovog spajanja (te opcionalno možemo specificirati i normale
i koordinata tekstura za svaki verteks). Ova funkcionalnost je dostupna i u A2D sa malom
razlikom da u A3D imamo jednu koordinatnu os više pa i za nju moramo specificirati
koordinate. Naprimjer, razmotrimo sljedeći isječak Processinga.
beginShape(TRIANGLE_STRIP);
vertex(30, 75, 0);
vertex(40, 20, 0);
vertex(50, 75, 0);
vertex(60, 20, 0);
vertex(70, 75, 0);
41
vertex(80, 20, 0);
vertex(90, 75, 0);
endShape();
Za ovaj složeni objekt pod nazivom „TRIANGLE_STRIP“ dobiti ćemo sliku 23. kada ga
renderiramo.
Slika 23 Renderiranje složenih objekata
5.3.1. Teksture
Teksture su jedna od najvažnijih tehnika u računalnoj grafici koje se sastoje od korištenja
slike kao papira u koji ćemo omotati neki 3D objekt sa ciljem da simuliramo da taj objekt je
načinjen od nekog materijala, da dobijemo realističnu površinu objekta ili možda neke efekte.
Slika 24 Slika objašnjava koncept tekstura u računalnoj grafici
Mapiranje tekstura na objekte je izazovan i kompleksan problem kada trebamo pridodati
teksturu nekom kompliciranom 3D objektu (koji još k tome je organske prirode). Da bi
42
pronašli pravilno mapiranje 2D slike u 3D objekt zahtjeva precizne matematičke tehnike koje
u svojim izračunima uzimaju u obzir rubove, presjeke, itd. Ako razmotrimo sliku 25. vidimo
koliko zapravo 3D objekt može biti kompleksan.
Slika 25 Slika demonstrira primjerom kako proces mapiranja tekstura može biti složen za određene 3D objekte
Kako bi u Processingu iskoristili teksture, pokazati ćemo to na jednostavnom primjeru kako
se to radi.
PImage img1, img2; void setup() {
size(240, 240, A3D); img1 = loadImage("beach.jpg"); img2 = loadImage("peebles.jpg"); textureMode(NORMAL); noStroke();
} void draw() {
background(0); beginShape(TRIANGLES); texture(img1); vertex(0, 0, 0, 0, 0); vertex(width, 0, 0, 1, 0); vertex(0, height, 0, 0, 1); texture(img2); vertex(width, 0, 0, 1, 0); vertex(width, height, 0, 1, 1); vertex(0, height, 0, 0, 1); endShape();
}
43
Kada kompajliramo gornji primjer i pokrenemo ga na Androidu dobivamo rezultat sa sljedeće
slike.
Slika 26 Primjer rada sa teksturama u Processingu
Iz gornjeg primjera vidimo kako raditi sa teksturama u Processingu na Androidu. Također,
prikazali smo još jedno važno svojstvo, a to je da sa beginShape i endShape u A3D možemo
iskoristiti kombinaciju više tekstura za različite dijelove jednog objekta.
5.3.2. Svijetlo
Android 3D također pruža lokalni model osvijetljenja baziran na OpenGL modelu. To je
jednostavan pravovremeni (eng. realtime) model osvijetljenja, gdje svaki izvor svijetlosti
sadrži 4 komponente:
Ambijent
Difuziju
Spekular
Emisiju
44
Zbroj tih 4 komponenata čini total. Ovaj model ne dopušta stvaranje sjena te može definirati i
do 8 različitih izvora svijetla. Odgovarajući izračuni za svijetlo zahtjevaju da se specificira
normala objekta. Android 3D podržava nekoliko tipova svijetla, a to su:
Ambijentalno – Ambijentalno svijetlo je takvo svijetlo koje ne dolazi iz nekog
specifičnog smjera, zrake svijetlosti sadrže osvijetljenje na sve strane tako da su
objekti ravnomjerno osvijetljenji sa svih strana. Ambijentalno svijetlo se gotovo uvijek
koristi u kombinaciji sa drugim tipovima svijetla.
o U Android Processingu definiramo ga funkcijom: ambientLight(v1, v2 ,v3, x,
y, z), gdje su v1, v2, v3 rgb boje svijetla, a x, y, z pozicija
Slika 27 Primjer ambijentalnog svijetla
Direkcionalno – Direkcionalno svijetlo dolazi iz nekog smjera i puno je jače na
dodirnim točkama objekta te zatim nakon toga slabi. Nakon što udari površinu
objekta, direkcionalno svijetlo će se raspršiti u svim smjerovima.
o U Android Processingu definiramo ga funkcijom: directionalLight(v1, v2, v3,
nx, ny, nz), gdje su v1, v2, v3 rgb boje svijetla, a nx, ny i nz vektor smjera
svijetla
Slika 28 Primjer direkcionalnog svijetla
Točkasto – Točkasto svijetlo zrači svijetlošču iz specificirane pozicije.
o U Android Processingu definiramo ga funkcijom: pointLight(v1, v2, v3, x, y,
z), gdje su v1, v2, v3 rgb boje svijetla, a x, y, z koordinate točke
45
Slika 29 Primjer točkastog svijetla
Pjegasto – Pjegasto svijetlo emitira svjetlost prema određenog konusu emitiranja tako
da onemogući prostoru emitiranja izvor svijetlosti
o U Android Processingu definiramo ga sa: spotLight(v1, v2, v3, x, y, z, nx, ny,
nz, angle, concentration) gdje su v1, v2 i v3 rgb boje svijetlosti, x, y, z su
koordinate konusa, nx, ny, nz specificiraju vektor smjera svijetlosti, angle
označava pod kojim kutem će konus biti i concetration označava eksponent
koji determinira centralni nagib konusa.
Slika 30 Primjer pjegastog svijetla
46
6. Kochova pahulja u 3D
Sada kada smo napravili kratak pregled kroz osnove OpenGL ES-a na Androidu iz dvije
različite perspektive, pokušati ćemo izmodelirati Kochovu pahulju u 3D-u. Kako više
naginjemo novijem pristupu razvoja Android grafike, koristiti ćemo Processing 2.0 za crtanje
našeg 3D fraktala.
Za početak prisjetimo se kako se crta Kochova pahulja u 2D-u. Iz teorije znamo da se
Kochova pahulja crta uz pomoć Kochove krivulje, a Kochova krivulja se dobiva tako da
zadani vektor podijelimo prvo na 3 jednaka dijela, te zatim obrišemo srednji dio te na
njegovom mjestu nacrtamo dva vektora koja se dodiruju u normali početnog vektora. Ovaj
proces ponavljamo rekurzivno za svaki od vektora koji imamo na platnu. Kochova krivulja
počinje od 1 vektora i njega rekurzivno dijeli, te na taj način tvori fraktal dok Kochova
pahulja za početni oblik uzima trokut, te cijelokupni postupak iz Kochove krivulje ponavlja za
svaku od stranica trokuta.
No pitanje se sada postavlja na koji način možemo nacrtati Kochovu pahulju u 3D-u. Da bi
cijelu priču iz 2D-a pretvorili u 3D moramo zamijeniti primitivne konstrukte. Jednostavnim i
brzim istraživanjem otkrili smo da Kochovu pahulju u 3D-u možemo nacrtati na dva načina.
Prvi način je da našu pahulju krenemo crtati od piramide. Na svaku stranicu početne piramide
nacrtati ćemo novu umanjenu piramidu. Na svaku od nacrtanih piramida nacrtati ćemo po još
jednu piramidu, itd. Ovim postupkom dobiti ćemo Kochovu pahulju kao što je prikazana na
sljedećoj slici.
47
Slika 31 Prvi način crtanja Kochove pahulje [3D Koch Snowflake, dostupno na:
http://blog.3dvision.com/2008/10/30/3d-koch-snowflake/]
Drugi način crtanja Kochove pahulje u 3D također kreće od piramide kao baze. No u ovom
slučaju pojedinu stranicu piramide ćemo podijeliti na 4 jednakostranična trokuta te na
srednjem izgraditi piramidu. U idućem koraku rekurzije to činimo za svaku stranicu trokuta
uključujući i novonastale trokute.
Slika 32 Drugi način crtanja Kochove pahulje [3D Koch snowflake, Dostupno na: https://encrypted-
tbn3.gstatic.com/images?q=tbn:ANd9GcT7GePIlCD-sSHFmcFl3OgYiojQo4rovsUVxT2YS7rEgozfG6AjUA]
S obzirom da nam drugi način crtanja je bio mnogo zanimljiviji od prvog odlučili smo se
implementirati drugi način. Uvidjeli smo da takvim crtanjem Kochove pahulje u 3D, gdje
pojedine stranice dijelimo na isti način kao što i crtamo Sierepinski trokut u 2D dobivamo
mnogo zanimljiviji i bogatiji oblik same pahulje. U nastavku ćemo razmotriti Android
Processing 2.0 kod naše implementacije Kochove pahulje.
48
6.1. Analiza izvornog koda
U ovom potpoglavlju analizirati ćemo naš izvorni kod.
import processing.opengl.*;
PrintWriter logger;
float pisquared = TWO_PI;
PImage tex;
FraktalniTrokut koch[]=new FraktalniTrokut[4];
void init_koch(PVector a, PVector b, PVector c, PVector d, int
dubina_rekurzije) {
koch[0] = new FraktalniTrokut(a, b, c, dubina_rekurzije);
koch[1] = new FraktalniTrokut(a, d, b, dubina_rekurzije);
koch[2] = new FraktalniTrokut(a, c, d, dubina_rekurzije);
koch[3] = new FraktalniTrokut(b, d, c, dubina_rekurzije);
}
void setup() {
logger = createWriter("calculations.txt");
//stroke(0);
//strokeWeight(1);
size(displayWidth, displayHeight, OPENGL); // OPO velicina
noStroke();
//fill(150,150,150,20);
//textureMode(NORMALIZED);
49
fill(255,0,0,120);
//noFill();
int tockaA = 200;
int dubina_rekurzije = 2;
PVector A = new PVector(-tockaA, 0, 0);
PVector B = new PVector(tockaA/2, 0, -175);
PVector C = new PVector(tockaA/2, 0, 175);
PVector D = new PVector(0, -tockaA * (sqrt(6) / 3), 0);
init_koch(
A, B, C, D,
dubina_rekurzije
);
}
void setup_camera() {
float tockaX=(mouseX / float(width)) * pisquared;
float pozicija_x=cos(tockaX);
float pozicija_y=sin(tockaX);
float radius=300.000;
camera(pozicija_x * radius, mouseY, pozicija_y*radius, // pogled
iz X, pogled iz Y, pogled iz Z
0.0, -50.0, 0.0, // center X osi, center Y osi, center Z
osi
0.0, -1.0, 0.0);
}
50
void draw() {
background(mouseY * (255.0/600), 255, 0);
lights();
//setup_camera();
pushMatrix();
translate(displayWidth / 2, displayHeight / 2);
//translate(nf(ax, 1, 2), nf(ay, 1, 2));
rotateX(mouseY * 0.01);
rotateY(mouseX * 0.01);
print("Rotated X: " + mouseY * 0.01);
print("Rotated Y: " + mouseX * 0.01);
scale(1);
for (int i=0;i<koch.length;i++) {
koch[i].display();
}
popMatrix();
}
class FraktalniTrokut {
PVector PointA;
PVector PointB;
PVector PointC;
FraktalniTrokut podijeljeni_trokuti[] = new FraktalniTrokut[6];
int rec;
float skaliranje;
FraktalniTrokut(PVector A,PVector B,PVector C, int recursion){
skaliranje = 0.7;
PointA = A;
51
PointB = B;
PointC = C;
rec = recursion;
rekurzija ();
}
void rekurzija () {
if (rec != 0) {
// racunamo 3 nova vektora koji dijele povrsinu
PVector PointAB2 = PVector.add(PointA,PointB);
PointAB2.div(2);
PVector PointAC2 = PVector.add(PointA,PointC);
PointAC2.div(2);
PVector PointBC2 = PVector.add(PointB,PointC);
PointBC2.div(2);
// racunamo sredisnju tocku na danom trokutu
PVector PointZ = PVector.add(PointA,PointB);
PointZ.add(PointC);
PointZ.div(3);
// racunamo vektor smjera normale u kojoj ce se spajati
trokuti
PVector PointAB = PVector.sub(PointA,PointB);
PVector PointAC = PVector.sub(PointA,PointC);
PVector PointH = PointAB.cross(PointAC);
PointH.normalize(); // normalizamo vektor na velicinu 1
// racunamo tocku u kojoj ce se spajati novi trokuti
PVector PointAAB2 = PVector.sub(PointA,PointAB2); // ovo je
polovica baznog vektora koji cini stranicu trokuta kojeg dijelimo
float a = PointAAB2.mag(); // racunamo velicinu tog vektora
52
float pheight = a * (sqrt(8) / 3) * skaliranje; // racunamo
visinu za novu piramidu, te prilagodavamo visinu tako da novi
trokuti nebudu preveliki
PointH.mult(-pheight); // dizemo tocku sa povrsine u zrak
PVector PointZH = PVector.add(PointZ,PointH);
podijeljeni_trokuti[0] = new
FraktalniTrokut(PointA,PointAB2,PointAC2,rec-1); // crtamo trokut 1
podijeljeni_trokuti[1] = new
FraktalniTrokut(PointB,PointBC2,PointAB2,rec-1); // crtamo trokut 2
podijeljeni_trokuti[2] = new
FraktalniTrokut(PointC,PointAC2,PointBC2,rec-1); // crtamo trokut 3
podijeljeni_trokuti[3]=new
FraktalniTrokut(PointZH,PointAC2,PointAB2,rec-1); // crtamo trokut 4
podijeljeni_trokuti[4]=new
FraktalniTrokut(PointZH,PointAB2,PointBC2,rec-1); // crtamo trokut 5
podijeljeni_trokuti[5]=new
FraktalniTrokut(PointZH,PointBC2,PointAC2,rec-1); // crtamo trokut 6
}
}
void display () {
if (rec==0) {
beginShape();
texture(tex);
vertex(PointA.x, PointA.y ,PointA.z);
vertex(PointB.x, PointB.y ,PointB.z);
vertex(PointC.x, PointC.y ,PointC.z);
endShape(CLOSE);
} else {
for (int i=0; i<podijeljeni_trokuti.length;i++) {
53
podijeljeni_trokuti[i].display();
}
}
}
}
6.2. Analiza različitih dubina rekurzije
Dubina rekurzije: 7
54
Slika 33 Kochova Pahulja u 3D sa dubinom rekurzije 7
Dubina rekurzije: 6
Slika 34 Kochova Pahulja u 3D sa dubinom rekurzije 6
Dubina rekurzije: 5
55
Slika 35 Kochova Pahulja u 3D sa dubinom rekurzije 5
Dubina rekurzije: 4
Slika 36 Kochova Pahulja u 3D sa dubinom rekurzije 4
Dubina rekurzije: 3
56
Slika 37 Kochova Pahulja u 3D sa dubinom rekurzije 3
Dubina rekurzije: 2
Slika 38 Kochova Pahulja u 3D sa dubinom rekurzije 2
57
7. Zaključak
U ovom seminarskom radu obrađivali smo u sklopu kolegija računalne grafike temu
pod nazivom fraktali. Tema je obrađena na dva načina. Prvi je s teorijskog stajališta općenito
o fraktalima kako bi ostale studente mogli upoznati i povezati s njihovim značenjem i
tematikom, a drugi je praktične prirode gdje smo analizirali - OpenGL ES iz dvije perspektive
– Java i Processing.
Fraktali predstavljaju u biti objekte koji daju jednaku razinu detalja neovisno o
razlučivosti koju koristimo, a njihova osnovna svojstva su samosličnost, fraktalna dimenzija i
oblikovanje iteracijom kao što smo i ranije naveli. Moguća je njihova podjela prema stupnju
samosličnosti i prema načinu nastanka.
Fraktalna umjetnost relativno je mlada u usporedbi s drugim umjetnostima, jer ne bi
mogla nastati bez uporabe računala, no fraktali su ipak s nama oduvijek. Najvjerovatnije se
upravo iz tih razloga ljudima i sviđaju. U njima pronalazimo nekakvu neobičnu ljepotu,
volimo gledati u njih, djeluju na nas umirujuće. Nalazimo ih posvuda u prirodi, pa i na nama
samima (ako malo bolje promotrimo ruku i šaku, vidjet ćemo da je svaki prst u omjerima
umanjena verzija ruke). Ljudi su ih intuitivno osjećali i prepoznavali kao načelo stvaranja
prirode, pa onda nije ni čudo da u povijesti umjetnosti nalazimo fraktale ne samo prije prvih
računala, nego i prije struje i parnoga stroja [Fraktali i umjetnost, Vesna Mišljenović, Zagreb
(2011./2012. br. 80), str. 224.]
58
Literatura
1. Developers-Android, Displaying Graphics with OpenGL ES, dostupno na:
http://developer.android.com/training/graphics/opengl/index.html, 25.01.2015. ;
2. Fractal Noise, Neil Blevins, dostupno na:
http://www.neilblevins.com/cg_education/fractal_noise/fractal_noise.html, učitano:
17.01.2015. ;
3. Hrvatski matematički elektronski časopis math.e, Galerija fraktala, V. Antočić, A.
Galinović, dostupno na: http://e.math.hr/galerija/galerija_print.html, učitano:
17.01.2015. ;
4. Interaktivna računalna grafika kroz primjere u OpenGL-u, M.Čupić, Ž.Mihajlović,
dostupno na: http://www.zemris.fer.hr/predmeti/irg/knjiga.pdf, učitano: 17.01.2015. ;
5. M. Pašić, Uvod u matematičku teoriju kaosa za inženjere, Skripta FER, Zagreb, 2005.
(57.-83.) ;
6. Neverinov blog, dostupno na:
http://blog.dnevnik.hr/blogodneverina/2010/02/1627237517/fasciniranost-
fraktalima.html, učitano: 17.01.2015. ;
7. Processing for Android, dostupno na: http://processing.flosscience.com/processing-
for-android, 25.01.2015. ;
8. Processing/processing-android, Joel Moniz, dostupno na:
https://github.com/processing/processing-android/wiki, 25.01.2015. ;
9. Processing & Android: Mobile app development made (very) easy, dostupno na:
http://blog.blprnt.com/blog/blprnt/processing-android-mobile-app-development-made-
very-easy, 25.01.2015.
10. Pythagoras Tree, dostupno na:
http://www.phidelity.com/blog/phidelity/blog/fractal/pythagoras-tree/, učitano:
17.01.2015. ;
11. Shane Bow The Chaos of Mandelbrot, dostupno na:
http://shanebow.com/projects/mandelbrot/, učitano: 17.01.2015. ;
12. Silvergreen, Deviant art, dostupno na: http://silvergreen.deviantart.com/art/Fractal-
Tree-1646228, učitano: 17.01.2015. ;
59
13. Uvod u fraktale, M.Paušić, dostupno na:
http://www.fer.unizg.hr/_download/repository/Uvod%20U%20Fraktale%20by%20Ml
aden%20Pausic.pdf, učitano: 17.01.2015. ;
14. Uvod u matematičke metode u inženjerstvu, K. Brdar, M. Dobrinić, R. Joksić,
Fraktali, dostupno na:
http://matematika.fkit.hr/novo/izborni/referati/dobrinic_joskic_brdar_fraktali.pdf,
17.01.2015. ;