Code: Select all
// 3D:tä CB:llä
//Tervetuloa ensimmäiseen CoolBasic-3D -tutoriaaliin ikinä. Kyseessä ei siis ole CoolBasic 3D:n opas, sillä sitä ei
//näillä näkymin ikinä julkaista, vaan tämä opas kertoo, kuinka CB:n 2D -komennoilla ja matikalla saadaan loihdittua
//näytölle 3D:tä - reaaliajassa. Valitettavasti täytettyjä kuvioita ei CB:n nopeusongelmien vuoksi voi käyttää (paljoa).
//Huomaa, että 2D-ominaisuudet ja perusasiat (typet, taulukot jne.) tulisi hallita hyvin ennen tämän lukemista.
//( en ole koskaan ennen kirjoittanut oppaita, joten valituksia ja muuta voi lähetellä CB:n foorumille, jossa
//häärin nikillä koodaaja)
//No niin, ensimmäisen oppitunnin kimppuun siis. Tässä oppitunnissa esittelen pienen ohjelman, joka
//piirtää kolmiulotteisia pisteitä näytölle. (sen ajaminen nyt on ihan suotavaa, eli paina F5 tai klikkaa keltaista
//nuolta näytön yläreunasta, jokaista kuviota ihailtuasi riittävästi saat seuraavan painamalla mitä tahansa nappulaa
//esc tai ruksi ikkunan yläreunassa sulkee ohjelman)
//Ensin tehdään projektion suorittava funktio. Annetaan sille nimeksi Dot3D, koska se piirtää pisteen kolmiulotteis-
//ten koordinaattien perusteella. Sille annetaan siis parametreiksi x,y ja z, joita käytetään yleisesti kaikkialla.
//Vektoreita käytetään myös kaksiulotteisessa ohjelmoinnissa, niitä näkee yhtenään muun muassa CB:ssä.
//Ai et ole törmännyt? Todennäköisesti olet. Esimerkiksi "PositionObject" ottaa parametrinä kaksiulotteisen vektorin,
//esim. (10,10). Kolmiulotteisiin vektoreihin lisätään vain syvyys, jolloinka (10,10):stä tulisi (10,10,0) koska z-arvo
// 0 on näytön pinta. Koska objektia liikutetaan näytön pintaa pitkin, ei z-koordinaattin kajota lainkaan.
//OpenGL:n koordinaattijärjestelmään tottuneena käsittelen z:koordinaattia siten, että negatiivinen z-arvo on
//näytön "sisällä" ja positiivinen sen "ulkopuolella", eli piste (0,0,-10) näkyy näytöllä, ja mikäli voitaisiin piirtää piste
//(0,0,10), se leijuisi näytön edessä. Ja kun piste menee kauemmas, mitä sille tapahtuu? Se lähenee näytön keski-
//pistettä. Kuten oikeastikin. Jos vaikka seisot auton vieressä, kun se lähtee, se näyttää kummasti pienenevän, sitä
//enemmän, mitä kauemmaksi pääsee. Jos sinulla on kaksi pistettä, jotka molemmat liikkuvat kauemmas, ne
//näyttävät lähenevän toisiaan -> viiva, jonka niiden väliin voisi piirtää, kutistuu. Samoin käy autolle, siinä vaan on
//hieman enemmän pisteitä kuin kaksi. Ja sitten se funktio.
Function Dot3D( x#, y#, z# )//projektoi ja piirtää pisteitä.
If z# > 0 Then Return 0//jos piste on "näytön ulkopuolella", sitä ei piirretä
If z# = 0 Then z# = -0.01 //z:lla jaetaan myöhemmin, ja nollallahan ei saa jakaa. 0,01 on riittävän lähellä nollaa.
//sx = x * (1/z)*500 Noh, miksikäs nämä kaksi riviä on kommentoitu? Nehän vekkulisti laskevat pisteen koordinaatit.
//sy = y * (1/z)*500 Vaan näissä on muutama vika: ensinnäkin sama laskutoimitus tehdään monta kertaa.
// Sen lisäksi nämä piirtävät 0,0,0:n vasempaan yläkulmaan, ja se halutaan keskelle.
p_s# = (1/z#)*100//perspective scalar (perspektiivikerroin). Tuo luku sata on joka resoluutiolla hieman eri luku,
// kokeilemalla löytää sopivan.
sx = x# * p_s# + ScreenWidth()/2//kerrotaan x perspektiivikertoimella, ja lisätään näytön puolikas (0,0,0 keskelle)
sy = y# * p_s# + ScreenHeight()/2
Dot sx,sy//piirretään piste näytölle
End Function //HUOM! Kolmiulotteisissa ohjelmissa tulee käyttää desimaalilukuja hyvin monissa asioissa.
// Esimerkiksi koordinaatit ja kertoimet ovat lähes aina desimaaleja ( floatteja )!
//Demonstroin käyttöä hieman..
Repeat//loopataan "taideteoksia", kunnes ohjelmasta erikseen poistutaan
For i = 0 To 99//tässä piirretään yhteensä sadan neliön kulmat, jokainen on yhden yksikön kauempana näytöstä
Dot3D( -10, 10, -i )//tästä näkeekin muuten hyvin klassisen junarata-efektin, eli pisteiden jonothan ovat suoria,
Dot3D( 10,-10, -i )//mutta näyttävät silti menevän keskemmälle
Dot3D( 10, 10, -i )
Dot3D( -10,-10, -i )
Next i
DrawScreen
WaitKey
For i = 0 To 259//tässä piirretään simppelin trigonometrian avulla spiraali, jossa jokainen piste on hiukan kauempana
ii# = i
Dot3D( Cos(ii*10)*10, -Sin(ii*10)*10, -ii/10 )
Next i
DrawScreen
WaitKey
For i = 0 To 7//kuutio
x = -1 + ( 2 * (i < 4) )//lasketaan koordinaatit järkyttävän logiikkaoperaattorirumban avulla.
y = -1 + ( 2 * (i Mod 2 = 0))
z = -1 - ( i = 2 Or i = 3 Or i = 6 Or i = 7 )
Dot3D( x,y,z )
Next i
DrawScreen
WaitKey
Forever
//Kannattaa kokeilla muokkailla tuota funktiota ja piirrellä erilaisia kuvioita, kuten nämä kolme esimerkkiäni.
//Ensi oppituntiin aion kasata jotain pinnoista ( kolmiot, yms. ). Jos nyt sellaista halutaan =)
REMSTART
Kopsasinpa tämän tähän ilman kommentteja ja turhia välejä. Jospa vaikka auttaa jotakuta hahmottamaan asian paremmin.
Function Dot3D( x#, y#, z# )
If z# > 0 Then Return 0
If z# = 0 Then z# = 0.01
p_s# = (1/z#)*100
sx = x# * p_s# + ScreenWidth()/2
sy =-y# * p_s# + ScreenHeight()/2
Dot sx,sy
End Function
REMEND
Code: Select all
//Hei taas, sinä joka jaksoit tänne saakka lukea =). Eli tällä kerralla höpöttelen kolmioista ja kaikesta niihin liittyvästä.
//Kuten varmaan jokainen tietää, kolmio muodostuu kolmesta kulmasta, jotka voidaan siis määritellä kolmella
//pisteellä. Kolmio on siitä jännä kuvio, että kaikki muut kuviot voi jakaa kolmioiksi, ja kolmion voi jakaa ainoastaan
//kahdeksi kolmioksi. Lisäksi kolmion voi tehdä yhdistämällä mitkä tahansa kolme pistettä. Näistä syistä kolmioita
//käytetään 3D-grafiikassa eniten.
//Sitten asiaan, eli tehdään funktio, joka piirtää kolmion. Kuten mainittu, täyttö on reaaliaikaisena liian hidasta,
//joten sitä ei voi käyttää. Tämä ajatellen niitä raukkoja, kuten minä, joilla on hidas kone :)
Function triangle(x1,y1,x2,y2,x3,y3)
Line x1,y1,x2,y2
Line x2,y2,x3,y3
Line x3,y3,x1,y1
End Function
//Ja tämä piirtääkin jo kolmioita vaivatta. Joskin kaksiulotteisia, hyi olkoon! Joten lisätään projektio:
Function Triangle3D(x1#,y1#,z1#,x2#,y2#,z2#,x3#,y3#,z3#)
If z1# > 0 Or z2# > 0 Or z3# > 0 Then Return 0//jos mikään piste on "näytön ulkopuolella", poistutaan
If z1# = 0 Then z1# = -0.01//estetään nollalla jako
If z2# = 0 Then z2# = -0.01
If z3# = 0 Then z3# = -0.01
p_s1# = (1/z1#)*100//projektiokertoimet
p_s2# = (1/z2#)*100
p_s3# = (1/z3#)*100
sx1 = x1# * p_s1# + ScreenWidth()/2//itse projektio
sy1 = y1# * p_s1# + ScreenHeight()/2
sx2 = x2# * p_s2# + ScreenWidth()/2
sy2 = y2# * p_s2# + ScreenHeight()/2
sx3 = x3# * p_s3# + ScreenWidth()/2
sy3 = y3# * p_s3# + ScreenHeight()/2
triangle(sx1,sy1,sx2,sy2,sx3,sy3)//piirtäminen
End Function
//Tuo toimikin jo sitten oikein kivasti. Toki sitä voisi optimoida ja lyhentää käyttämällä tyyppejä tai taulukoita, mutta
//itse en pidä taulukoiden, tyyppien ja memblokkien sekakäytöstä. Mikäli jossain tutoriaalissa tarvitaan jotain, käytän
//todennäköisimmin tyyppejä.
//Ja sitten muutama esimerkki:
Repeat
For i = 0 To 9//piirretään kolmioita, jotka etääntyvät, tulee kiva perspektiiviefekti
Triangle3D(-1,-0.75,-i,0,0.75,-i,1,-0.75,-i)
Next i
DrawScreen
WaitKey
For i = 0 To 259//edellisen oppitunnin spiraaliefekti, muokattu versio. Toki viivafunktio olisi parempi tähän, mutta sellaisen osaat varmaan tehdä itsekin.
ii# = i
Triangle3D( Cos(ii*10)*10, -Sin(ii*10)*10, -ii/10,Cos(ii*10)*10, -Sin(ii*10)*10, -ii/10,Cos((ii-1.0)*10.0)*10.0, -Sin((ii-1.0)*10.0)*10.0, (-ii+1)/10.0 )
Next i
DrawScreen
WaitKey
ClearKeys
Repeat//kolmio, jota trigonometriahäsellyksen avulla pyöritellään ja liikutetaan eestaas
ang# = ang# + 2
Triangle3D( Cos(0+ang),-Sin(0+ang),Cos(ang)-2,Cos(120+ang),-Sin(120+ang),Cos(ang)-2,Cos(240+ang),-Sin(240+ang),Cos(ang)-2 )
DrawScreen
Until GetKey()
Forever
//Tästäpäs tulikin lyhyt. Mutta koska pitäisin nämä mielelläni suoraan ajettavan ohjelman muodossa,
//jatkan kolmososassa, sitten katsotaan luultavasti backface cullingia ja hidden line removalia.
REMSTART
Ja tässäpä tämä funkkari, paranneltuna painoksena (otettu periaatteessa turha 'välikutsu' pois)
ilman kommentteja:
Function Triangle3D(x1#,y1#,z1#,x2#,y2#,z2#,x3#,y3#,z3#)
If z1# > 0 Or z2# > 0 Or z3# > 0 Then Return 0
If z1# = 0 Then z1# = -0.01
If z2# = 0 Then z2# = -0.01
If z3# = 0 Then z3# = -0.01
p_s1# = (1/z1#)*100
p_s2# = (1/z2#)*100
p_s3# = (1/z3#)*100
sx1 = x1# * p_s1# + ScreenWidth()/2
sy1 = y1# * p_s1# + ScreenHeight()/2
sx2 = x2# * p_s2# + ScreenWidth()/2
sy2 = y2# * p_s2# + ScreenHeight()/2
sx3 = x3# * p_s3# + ScreenWidth()/2
sy3 = y3# * p_s3# + ScreenHeight()/2
Line sx1,sy1,sx2,sy2
Line sx2,sy2,sx3,sy3
Line sx3,sy3,sx1,sy1
End Function
REMEND
Code: Select all
//Noniin, sinä joka olet edelleen tänne saakka päässyt! Alkuperäiseen suunnitelmaani tuli hienoinen muutos, joten
//tässä osassa käsitelläänkin backface cullingin lisäksi rotaatiota, eli pyörimistä, eikä hidden line removalia. Siitä
//joskus myöhemmin =) . Asiaan: ohjelmassa F1 asettaa backface cullingin päälle/pois ( kyseinen ominaisuus
//siis tekee takana olevista sivuista näkymättömiä), joka tosin toimii vain yhdessä piirtotilassa, viivapiirrossa.
//F5 selaa piirtotiloja, joita on neljä: pisteet, viivat, täyttö ja täyttö viivoilla. Tämä toimii siis hyvin pitkälti
//samalla tavalla kuin Aavesoturin objviewer, joskaan objekteja ei voi liikuttaa eikä vaihtaa. Kuutiota voi tosin
//pyörittää numpadin näppäimistä 2, 8, 4, 6, 7 ja 9. F3 asettaa automaattisen pyörityksen ON/OFF. Nyt
//kannattanee ajaa kyseinen ohjelma, painat siis F5 tai klikkaat keltaista nuolta editorin ylälaidassa.
//Nyt, kun tiedät, mitä se tekee, seuraa selitys siitä, kuinka se toimii:
//Tehdään vakiot näytön keskipisteen koordinaateista ( screenwidth() divided by 2 -> screenwd2 )
Const screenwd2 = 200//, sillä funktion kutsuminen + jakaminen joka pisteessä on aika raskasta, usko tai älä =)
Const screenhd2 = 150
Dim vect(7,4) As Float//tehdään taulukko vektoreista. Siinä on siis kuution vektorit, kaikki kahdeksan. Niistä
// tallennetaan x-, y- ja z- koordinaatit, sekä sx ja sy eli projektoidut koordinaatit.
For i = 0 To 7 //wanhalla tutulla logiikkarumballa lasketaan kuution kulmien koordinaatit.
vect(i,0) = -1 + 2*(i<4)
vect(i,1) = -1 + 2*((i Mod 2) = 0)
vect(i,2) = -1 + 2*( i = 0 Or i = 1 Or i = 4 Or i = 5 )
Next i
Dim tri(11,2)//sitten kolmiotaulukko, joka sisältää siis jokaisessa kolmiossa olevien vektorien järjestysnumerot.
//sivuja on siis kuusi, ja jokainen kun jaetaan kahtia, saadaan 12 kolmiota, joissa kaikissa luonnollisesti 3 kulmaa.
Function TriFill(x1,y1,x2,y2,x3,y3) //hiukan nopeammaksi muokattu versio CB SDK:n trifillistä ( kiitos atomimallille )
If y2<y1 Then 'jos p2 on ylempänä kuin p1 vaihdetaan niiden paikkaa
tmp=y1
y1=y2
y2=tmp
tmp=x1
x1=x2
x2=tmp
EndIf
If y3<y1 Then 'jos p3 on ylempänä kuin p1 vaihdetaan niiden paikkaa
tmp=y1
y1=y3
y3=tmp
tmp=x1
x1=x3
x3=tmp
EndIf
If y3<y2 Then 'jos p3 on ylempänä kuin p2 vaihdetaan niiden paikkaa
tmp=y2
y2=y3
y3=tmp
tmp=x2
x2=x3
x3=tmp
EndIf
'pisteet ovat nyt järjestyksessä
'ylhäältä alas p1(x1,y1), p2(x2,y2), p3(x3,y3)
dy1=y2-y1'pystysuora matka p1:sta p2:seen
dx1=x2-x1'vaakasuora matka p1:sta p2:seen
dy2=y3-y1'pystysuora matka p1:sta p3:meen
dx2=x3-x1'vaakasuora matka p1:sta p3:meen
If dy1 Then 'jos kolmion yläosa on pidempi kuin 0
'käydään läpi kaikki vaakaviivat kolmion yläosassa(p1-p2)
For i = y1 To y2
'lasketaan seuraava x-koordinaatti p1:stä p2:seen
ax=x1+((i-y1)*dx1)/dy1
'lasketaan seuraava x-koordinaatti p1:stä p3:meen
bx=x1+((i-y1)*dx2)/dy2
Box ax,i,bx-ax,1 'piirretään viiva kolmion reunojen välille
Box ax+(bx-ax),i,-(bx-ax),1
Next i
EndIf
dy1=y3-y2'pystysuora matka p2:sta p3:meen
dx1=x3-x2'vaakasuora matka p2:sta p3:meen
If dy1 Then 'jos kolmion alaosa on pidempi kuin 0
'käydään läpi kaikki vaakaviivat kolmion alaosassa(p2-p3)
For i = y2 To y3
'lasketaan seuraava x-koordinaatti p2:stä p3:meen
ax=x2+((i-y2)*dx1)/dy1
'lasketaan seuraava x-koordinaatti p1:stä p3:meen
bx=x1+((i-y1)*dx2)/dy2
If bx>ax Then
Box ax,i,bx-ax,1 'piirretään viiva kolmion reunojen välille
Else
Box ax+(bx-ax),i,-(bx-ax),1
EndIf
Next i
EndIf
EndFunction
//ja tästä eteenpäin taas allekirjoittaneen omaa koodia =)
Function project(i)//Tekee projektion. Z-koordinaattia ei tarkisteta, koska se ei voi olla nolla tai enempää.
p_s# = (1/vect(i,2))*screenwd2 //lasketaan projektioskalaari
vect(i,3) = (vect(i,0) * p_s#) + screenwd2//itse projektio
vect(i,4) = (vect(i,1) * p_s#) + screenhd2
End Function
Function Draw_Tri( i, mode=0 ,bcull = 1 )//piirtää kolmion, parametreinä piirtotyyppi ja bcull päällä/pois
sx1# = vect(tri(i,0),3) //haetaan koordinaatit muuttujiin, ihan mukavuuden vuoksi. nämä ovat siis kolmion pisteiden näyttökoordinaatit
sy1# = vect(tri(i,0),4)
sx2# = vect(tri(i,1),3)
sy2# = vect(tri(i,1),4)
sx3# = vect(tri(i,2),3)
sy3# = vect(tri(i,2),4)
If bcull = 0 Or (((sx2 - sx1 ) * ( sy3 - sy1) - (sx3 - sx1)*(sy2 - sy1))<=0) Then//mikäli bcull ei ole päällä, tai sivu
//läpäisee backface cull-testin eli sen pisteet ovat myötäpäivään kasvavassa järjestyksessä ( eli se 'osoittaa'
//kameraa kohti), se piirretään. backface culling tapahtuu siis tuossa yhdessä ainoassa laskussa, jonka tulos siis
//on enemmän kuin nolla, mikäli sivua EI piirretä, ja nolla tai vähemmän, mikäli se piirretään.
Select mode//piirretään oikealla piirtotyypillä
Case 0//pisteet
Dot sx1, sy1
Dot sx2, sy2
Dot sx3, sy3
Case 1//viivat
Line sx1, sy1, sx2, sy2
Line sx2, sy2, sx3, sy3
Line sx3, sy3, sx1, sy1
Case 2//täytetty
Color 0,0,255
TriFill(sx1, sy1, sx2, sy2, sx3, sy3)
Color 255, 255, 255
Case 3//täytetty + viivat
Color 0,0,255
TriFill(sx1, sy1, sx2, sy2, sx3, sy3)
Color 255, 255, 255
Line sx1, sy1, sx2, sy2
Line sx2, sy2, sx3, sy3
Line sx3, sy3, sx1, sy1
Default
End Select
EndIf
End Function
Function rotate( i, x#, y#, z#, ang# )//pyöritysfunktio! tämän kanssa tuli ainakin
//itselleni suurimmat ongelmat aloittaessani 3D:n tekemisen CB:llä
//Kvaternio. Iso, tärkeä juttu, tässä selittelen siksi hieman teoriaa. Kvaternio on kompleksilukujen nelikomponenttinen
//laajennus muotoa t + xi + yj + zk. Eli koska vektorin kiertoa (=pyörimistä) vastaavaa kolmilukuista vastinetta
//kvaterniolle ei ole ( matemaattisesti todistettavissa ), käytetään kvaterniota. Ja jos yrittää olla niitä käyttämättä, on
//fakta, että törmäät ns. "Gimbal Lock":iin. Kuvitteles, että pyörität jotain 90 astetta z-akselin suunnassa. No,
//mites sitten, kun pitäisi pyörittää y-suunnassa? Eri sivu osoittaa ylös, ja hämäävästi pyöritätkin sitä objektin
//x-akselin suunnassa. Vaikea käsittää aluksi, mutta jos ei jaksa kvaternioita käyttää, siihen törmää.
//Ne on keksitty 1843, muttajäivät myöhemmin keksityn vektorin taakse, jos jotakuta vaikka sattuu kiinnostamaan
//:D ja se onkin samalla syy, mikset todennäköisesti ikinä törmää näihin koulussa tai opiskellessasi. Niitä ei käytetä.
//paitsi 3D-grafiikassa, jossa niitä on PAKKO käyttää.
//Tämä koodinpätkä siis muuttaa akselin ja kulman ( akselin ympäri pyöritään kulman verran ) kvaternioksi,
//joka sitten muutetaan matriisiksi ja kerrotaan vektorilla. Kuulostaa vaikealta kuin on.
sin_a# = Sin( ang/2 )
qx# = x * sin_a//huomaa, että nelikomponenttisena laajennuksena kvaterniossa on x:n, y:n ja z:n lisäksi w.
qy# = y * sin_a
qz# = z * sin_a
qw# = Cos( ang/2 )
//Matriisi, heti päälle toinen iso juttu. Matriisi on siis kaksiulotteinen loota lukuja, tähän tapaan:
//[ 3, 2, 9 ]
//[ 5, 7, 3 ]
//[-6, 2, 0 ]
//yllä on 3X3-matriisi, koska siinä on kolme lukua sekä vaaka-että pystysuunnissa. Luvut voivat olla mitä
//vain, eikä niiden välillä tarvitse olla mitään sidettä. (ja oikeasti lukujen välissä ei ole pilkkuja, lisäsin ne selkeyden
//vuoksi) No, mitäs ihmettä näillä sitten tekee? No, niitä voi kertoa keskenään:
//[ A, B, C ] [ J, K, L ] [ A*J + B*M + C*P, A*K + B*N + C*Q, A*L + B*O + C*R ]
//[ D, E, F ] X [ M, N,O ] = [ D*J + E*M + F*P , D*K + E*N + F*Q, D*L + E*O + F*R ]
//[ G, H, I ] [ P, Q, R ] [ G*J + H*M + I*P, G*K + H*N + I*Q, G*L + H*O + H*R ]
//Niin hirveältä kuin se näyttääkin, ei se loppujen lopuksi ole hirveän vaikeaa, etenkin kun sitä tuossa muodossa
//varsin harvoin käytetään. Nyt tuleekin jotain paljon, paljon hyödyllisempää: vektorin voi esittää myös matriisina,
//kas näin:
//[x]
//[y]
//[z]
//3*1 -matriisina siis. Ja tämä kun kerrotaan wanhan tutun 3*3 -matriisin kanssa, temppu näyttää tältä:
//[A, B, C] [x] [ A*x + B*y + C*z ]
//[D, E, F ] X [y] = [ D*x + E*y + F*z ]
//[G, H, I] [z] [ G*x + H*y + I*z ]
//Paljon mukavampi kuin 3*3 X 3*3, eikö vain? Noniin, jatketaan:
//Tässä koodissa varsinaista muunnosta ei tehdä, tai siis matriisia ei tallenneta mihinkään. Mutta kyllä sen sieltä huomaa
//kun tarkasti katsoo. Esimerkiksi x:t, y:t ja z:t, joilla matriisi kerrotaan, suorastaan hyppäävät silmiin. ja niiden jälkeen tulee
//aina yksi matriisin solu. Mutta mitäs kehveliä?! Tuolla seassahan on kvaternion koordinaatteja seassa! Siinäpä se nerous piilee;
//kvaternion avulla lasketaan pyöritysmatriisi. Pyöritysmatriisin voisi laskea myös ilman kvaterniota, mutta silloin törmäisimme taas
//wanhaan ystäväämme Gimbal Lockiin. ( pahoittelen, että tämä pyörittelyosuus on hankala, mutta se on vaikea asia, etenkin selittää )
xx# = (vect(i,0) * (1 -(2 * (qy^2)) -(2 * (qz^2)) )) + (vect(i,1) * (2*qx*qy - 2*qz*qw)) + (vect(i,2) * (2*qx*qz + 2*qy*qw))
yy# = (vect(i,0)*(2*qx*qy + 2*qz*qw)) + (vect(i,1) * (1 -(2 * (qx^2)) -(2 * (qz^2)) )) + (vect(i,2) * (2*qy*qz - 2*qx*qw))
zz# = (vect(i,0)*(2*qx*qz - 2*qy*qw)) + (vect(i,1)*(2*qy*qz + 2*qx*qw)) + ( vect(i,2) * (1 -(2 * (qx^2)) -(2 * (qy^2)) ))
vect(i,0) = xx//sitten muistetaan vielä siirtää vektoreihin saakka nämä koordinaatit(välimuuttujat olivat pakollisia, koska jos vect(i,0)
vect(i,1) = yy//muuttuisi ylemmässä koodissa, se vaikuttaisi y:n laskemiseen, jonka muuttuminen vastaavasti z:n laskemiseen, ja kuutiohan
vect(i,2) = zz//vallan vääristyisi)
End Function
Function SetTri(i,v1,v2,v3)//parametreiksi annetaan kolmion vektorien järjestysluvut ja itse kolmion järjestysluku.
//Tämä funkkari on tehty ihan vain vähentämään rivejä.
tri(i,0) = v1
tri(i,1) = v2
tri(i,2) = v3
End Function
//Tässä asetetaan kolmioiden kärjiksi oikeat vektorit. vaikeaksi menee, mutten mitään yhtenevyyttä
//löytänyt näiden välillä, joten en saanut sitä for-loopissa tai vastaavassa tehtyä.
settri(0,0,4,2):settri(1,0,1,4):settri(2,0,2,1):settri(3,6,2,4):settri(4,6,4,7):settri(5,6,7,2)
settri(6,3,7,1):settri(7,3,1,2):settri(8,3,2,7):settri(9,5,1,7):settri(10,5,4,1):settri(11,5,7,4)
bculled = 1//backface cull ON/OFF
mode = 0//piirtotyyli
control = 1//liikutellaanko kuutiota itse
Repeat
If control = -1 Then //oletusarvoiset pyörimiskulmat
xang# = 0.8
yang# = 0.4
zang# = 0.6
Else//ohjaus päällä?
xang = KeyDown(80) - KeyDown(72)
yang = KeyDown(75) - KeyDown(77)
zang = KeyDown(73) - KeyDown(71)
EndIf
For i = 0 To 7//kaikki kulmat
rotate( i, 1, 0, 0, xang )//pyöritetään x-akselin suhteen x-kulma, y-akselin suhteen y-kulma ja z-akselin
rotate( i, 0, 1, 0, yang )//suhteen z-kulma
rotate( i, 0, 0, 1, zang )
vect(i,2) = vect(i,2) - 4//liikutetaan kuutiota kauemmas, jotta se näkyy kokonaan ruudulla
project(i)
vect(i,2) = vect(i,2) + 4//liikutetaan se takaisin. Vaan miksei se voisi olla siinä koko aika? Koska kaikki
//pyöriminen tapahtuu origon (eli (0,0,0)) ympäri. Vaikka sitä pyöritettäisiin sen ollessa muualla, se pyörisi
//yhä origon ympäri, jolloin se näyttäisi kiertävän laajassa ympyrässä.
Next i
For i = 0 To 11//piirretään kaikki kolmiot oikealla modella ja cull -arvolla
Draw_Tri( i, mode, bculled )
Next i
If KeyHit(59) Then//vaihdellaan bcullia, jos F1 painettu
If bculled = 1 Then bculled = 0 Else bculled = 1
EndIf
If KeyHit(63) Then mode = mode + 1//lisätään modeen yksi, jos F1 painettu
If mode = 4 Then mode = 0//jos mentiin yli, palataan nollaan
If mode = 0 Then bculled = 0//bcull päällä vain viivamodessa
If mode = 2 Or mode = 3 Then bculled = 1
If KeyHit(61) Then control = -control//vaihdetaan autorotaatio ON/OFF, jos F3 painettu
DrawScreen
Forever