3D
Kolmemõõtmeliste lahenduste loomiseks on mitmeid raamistikke loodud, kus
kasutajal võimalus kujundid ja kaamera sobivasse kohta sättida ning sealtkaudu
meeldivat ruumilist pilti vaadata. Veebigraafika üks abiline näiteks three.js
nime all. Samas lihtsamat ruumilisuse efekti kannatab täiesti ka harilike
kahemõõtmeliste joonistusvahendite abil tekitada
Kaugemal väiksemaks
Arvutijooniste puhul tuleb ikka eristada ekraani- ja maailmakoordinaate. Päris
lihtsate jooniste korral võib ette kujutada, et üks piksel ekraanil on üks
meeter looduses. Või siis üks piksel vastab inimese pikkuse ühele
sentimeetrile. Kõiksugu muude suurenduste puhul aga peab väärtused sobiva
koefitsiendiga läbi korrutama. Samuti ei pruugi me tahta arve lugeda
joonistusala vasakust ülanurgast, vaid mugavam võib olla arvutada mõnest rohkem
joonise keskel olevast punktist - selle väärtuse saab arvutuste juures juurde
liita. Matemaatikaõpikus oleme harjunud, et y-telg suundub üles, arvutiekraanil
suundub see esmalt alla. Ka selle saab märgimuutusega paika sättida. Kolmanda
mõõtme juures tuleb maailmakoordinaatidest ekraanikoordinaatideks arvutades
lihtsalt üks tehe juurde - x ja y tuleb kaugusega (z) läbi jagada. Ehk siis
sama suur asi kaks korda kaugemal näeb kaks korda väiksem välja. Sobivaks
nägemiseks tulevad arvud suurenduskordajaga läbi korrutada. Siin puhul selleks
valitud kümme. Muutujad keskx ja kesky tähistavad koordinaatide alguspunkti
joonisel. Funktsioone ex ja ey kasutatakse ekraani x-i ja y-i arvutamiseks
vastavalt maailmakoordinaatides punkti kolme mõõtme väärtustele.
var keskx=200;
var kesky=150;
var suurendus=10;
function ex(px, py, pz){ //x ekraanil
return keskx+suurendus*px/pz;
}
function ey(px, py, pz){
return kesky-suurendus*py/pz;
}
Joonistamise puhul tuleb siis iga kord sobivas kohas lihtsalt vastavad
funktsioonid välja kutsuda
g.lineTo(ex(x, y, z), ey(x, y, z));
Ehk siis leitakse kolmemõõtmelistele algandmetele vastavad kahemõõtmelised
punktid ekraanil. Joonisele tehakse tsükli abil postirida. Posti alumise otsa y
on 0, ülemise oma 40 ühikut. Kaugused viiest viiekümne ühikuni.
3D
Väikese ettekujutuse tulemusena võib lehel täiesti viisakat postirida näha.
Ülesandeid
Pane näide tööle
Katseta postide mitmesuguste kõrguste ja vahedega
Loo sarnane postirida ka vaatajast paremale
Paiguta postide otsa väikesed ringid nagu tänavalaternad
Kasutaja asukoha muutmine
Kolmemõõtmelises graafikas võivad liikuda kujundid, võib liikuda ka aga kaamera
ehk vaataja ise. Kui vaatesuund jääb otse ette, siis polegi arvutamisel muud
muret, kui tuleb ainult kasutaja asukoht kujundite asukohast maha lahutada.
Ekraani x-koordinaadi arvutamine siis:
function ex(px, py, pz){ //x ekraanil
return keskx+suurendus*(px-vaatajax)/(pz-vaatajaz);
}
Ehk siis nii x- kui z- koordinaadi puhul on vastav tehe tehtud. Mida ettepoole
ise liikuda, seda lähemale tulevad kujundid. Mida ülespoole minna, seda enam
paistavad kujundid allpool. Vaataja sammu muutuja näitab, kui pikkade hüpetega
ta liigub. Juurde nupuriba vaataja andmete muutmiseks ning tekibki juba julgem
ruumilise vaatamise tunne.
3D
Vaade eest
ning vaade pärast mõningast üles- ja vasakule poole liikumist.
Ülesandeid
Pane näide tööle
Koosta kujundiks nelinurkse varjualuse sõrestik - postid ja katusepüramiid.
Vaata seda mitmest asukohast
Koosta kujundiks kuuenurkse varjualuse sõrestik, vaata
Koosta kujundiks kasutaja määratud nurkade arvuga varjualuse sõrestik
Kolmemõõtmeliste andmete objekt
Üksikuid punkte ja jooni arvutada ja kuvada saab täiesti tavaliste muutujatega.
Kui aga vaja koos hakata liigutama hulgast punktidest koosnevaid kujundeid,
siis tekib üksikuid punkte tülikalt suurel hulgal. Objektitüüpide ja objektide
abil aga on võimalik neid mugavamalt hallata, neile ühekorraga käsklusi jagada.
Samuti saab niimoodi mitmemõõtmelised arvutustehted nõnda koodi sisse ära
peita, et hilisema töö juures ei pea nii palju arvutusvigade pärast muretsema,
kui kood algul korralikult üle kontrollitud sai.
Vektor
Punkt ja vektor mõnevõrra sarnased nähtused. Esimesega küll oleme ehk enam
harjunud tähistama asukohta ning teisega liikumist. Aga iseenesest mõlemal on
vajalik arv mõõtmeid ning saab külge panna arvutusteks vajalikud käsud, nii et
otsest põhjust eraldi tüüpide loomiseks ei ole. Mõistet asukohavektor ka
täiesti kasutatakse, nii et las siis siingi piirdutakse ühe tüübiga kolme
koordinaadiga määratud suuruse tähistamiseks. Juurde levinud funktsioonid
liitmise ja lahutamise kohta. Samuti sisu tekstina väljastamiseks. Kusjuures
tähele tasub panna, et praeguse kahe vektori liitmisel tekib uus, kolmas
vektor, esialsete vektorite koordinaadid ei muutu.
Objektidest andmete tekstina välja küsimiseks on Javaskriptil olemas mugav JSON
(JavaScript Object Notation) - vorming. Andmed paigutatakse looksulgude vahele.
Sinna sisse järgemööda tunnuse nimi(võti) ning kooloni taga järgnev väärtus.
Nagu näiteks siin algandmed
{"x":2,"y":4,"z":6}
Käsklus JSON.stringify() teeb objektist sarnase andmetega stringi. Kui mõnikord
on vaja andmeid tekstist tagasi terviklikuks objektiks muuta, siis selleks
sobib käsklus JSON.parse().
Nüüd aga kolmemõõtmelise vektori kood
3D
Töö tulemus kihil:
{"x":2,"y":5,"z":6}
Ülesandeid
Pane näide tööle
Lisa vektorile käsklus korruta(arv), mis väljastab uue vektori, kus kõik
esialgse vektori koordinaadid on selle arvuga korrutatud. Veendu, et tulemus
toimib.
Kahest punktist joon
Vektor hoiab ühe punkti kolm koordinaati ilusti koos. Kui tahta, et joone
andmeid saaks ühe tervikuna käsitleda, siis tuleb omakorda joone kaks otspunkti
üheks tervikuks siduda. Siin seda ka tehakse. Joonele luuakse punktide jaoks
massiiv, kus kohal 0 on üks otspunkt ning kohal 1 teine.
Arvestades varasemat näidet vaataja asukoha liigutamise kohta, lisatakse eraldi
tüüp ja objekt ka vaataja asukoha meelespidamiseks ning vastavalt sellele Joone
joonistuskäskluses ekraanikoordinaatide arvutamiseks. Valemid sarnased kui
enne, lihtsalt nüüd on need funktsioonide sisse pandud ja funktsioonid omakorda
objektiks kapseldatud, et juhtkoodis tekkida võivat segadust vähemaks saada.
Kui tükid olemas, siis nende ühendamine võiks juba üsna lihtsalt minna. Praegu
luuakse kõigepealt uus Joon, mille otspunktide koordinaatideks saavad kaks
Vektor3D-d oma väärtustega. Muud toimetused pandi alusta-funktsiooni sisse,
sest tahvlile pole võimalik lehe päises avanemise ajal ligi saada. Küll aga on
tahvel kättesaadav pärast lehe laadimist body onload-sündmuse peale käivitatava
funktsiooni alusta() sees. Vaatajale määratakse asukoht (hetkel nullpunkt),
joonistamise graafiline kontekst ning koordinaatide nullkoha asukoht ekraanil
(hetkel tahvli keskkoht). Pärast joonistuskäsklust võikski joon ekraanil näha
olla.
var j1=new Joon(new Vektor3D(-20, 0, 5), new Vektor3D(-20, 40, 5));
var vaataja;
function alusta(){
var tahvel=document.getElementById("tahvel1");
vaataja=new Vaataja(new Vektor3D(0, 0, 0),
tahvel.getContext("2d"), tahvel.width/2, tahvel.height/2);
j1.joonista(vaataja);
}
Edasi töötav kood tervikuna.
3D
Ülesandeid
Pane näide tööle
Joonista nõnda ekraanile kaks Joont
Lisa Joonele värvi omadus
Joonista ekraanile kaks eri värvi joont
Muuda Vaataja asukohta
Joonte kogum
Üksikut joont on tõenäoliselt lihtsam ilma igasuguste objektideta joonistada.
Kui mitu joont aga moodustavad uue terviku, siis on see mõistlik uude kesta
panna - nii on võimalik seda hiljem korraga joonistada, liigutada või värvida.
Kogumi juurde tuleb massiiv millesse andmeid lisada. Kogumile antud
joonistuskäsklus käib läbi kõik kogumis olevad jooned ning kutsub välja neist
igaühe joonistuskäskluse. Praegu siin juures ka käsklus vaataja tahvli
puhastamiseks, aga selle saab mujale panna, kui tekib soov mitu kujundit
järjestikku samale tahvlile joonistada.
function KujundiKogum(){
this.kujundid=new Array();
this.lisaKujund=function(k){this.kujundid.push(k);}
this.joonista=function(vaataja){
vaataja.g.clearRect(0, 0, 400, 300);
for(var i=0; i
Edasi juba kood tervikuna.
3D
Lehel saab nõnda vaatajaga ringi liikuda.
Ülesandeid
Pane näide tööle
Koosta joontest kaks kogumit: kahest joonest T-täht ning kuuest joonest
tetraeeder (kolmnurkne püstprisma). Kuva mõlemad ekraanile. Vaata neid kaamera
liigutamise abil mitmelt poolt.
Lisa kogumile omaduseks toon. Kuva kumbki kogum vastava värviga ekraanile.
Lisa kogumile käsklus teeSamm, mis siis kogumis olevaid kujundeid etteantud
vektori jagu edasi liigutab. Lisa lehele nupp ühe ekraanil oleva kogumi
liigutamiseks.
Lisa kogumile muutuja liikumissammu vektorina hoidmiseks. Pane kumbki kujund
ühtlase kiirusega tema küljes olevas suunas liikuma.
Reaalse mõõtkava arvestamine
Siiani tehtud näidetes jagati kaugustunnetuse saamiseks x ja y-koordinaat
lihtsalt kaugusega läbi ning vajadusel korrutati suurenduskordajaga, et pilt
enamvähem sobivas suuruses oleks. Tõsielulise olukorra järele tegemisel aga
saab andmed ka täpsemalt näiteks meetrites välja arvestada ning siis vaateaval
mõttelisel kaugusel olevale kilele projitseerida. Ning edasi otsustada, millise
suurendusega projektsioonikile punktid arvutiekraani piksliteks ümber arvutada.
Kolmnurga valemite järgi on vaadeldava punkti ühe (nt. x) mõõtme koordinaadi ja
silmast kauguse suhe sama kui selle punktini viiva joone lõikekoha kilel ja
kile kauguse suhe. Sellise arvutuse järgi õnnestub leida koht kilel
(px-vaatajax)*kilekaugus/(pz-vaatajaz)
Kuna vaataja ei pruugi olla koordinaatide nullpunktis ning tavajuhul on
vaatekile mõõtmed pigem võrreldav ekraanipikslite arvuga sentimeetrites, siis
saab kolmemõõtmelised koordinaadid kahemõõtmelisteks arvutada järgnevalt.
var suurendus=100; //sentimeetrit meetri kohta
function ex(px, py, pz){ //x ekraanil
return keskx+suurendus*(px-vaatajax)*kilekaugus/(pz-vaatajaz);
}
Edasi juba programmikood tervikuna
3D
Samuti kaheksanurkse telgi vaated mitmest asukohast.