offline
- Srki_82
- Moderator foruma
- Srđan Tot
- Am I evil? I am man, yes I am.
- Pridružio: 12 Jul 2005
- Poruke: 2483
- Gde živiš: Ljubljana
|
GLScene je 3D engine za Delphi zasnovan na OpenGLu. Sa njim je moguce vrlo brzo kreirati zanmljive 3D scene, aplikacije, igre... U sebi trenutno sadrzi 3D, script, physic i sound engine... takodje sadrzi rutine za lak rad sa misem, dzojstikom, tastaturom sto ga cini vrlo dobrim alatom za pravljenje igara u Delphiu.
Hompage: http://glscene.sourceforge.net/index.php
Najnoviju verziju mozete skinuti uz pomoc TortoiseCVS. To je program koji radi preko CVS protokola. Mozete ga skinuti sa http://www.tortoisecvs.org/index.shtml , a uputstvo za skidanje GLScene (CVS) mozete pronaci na http://sourceforge.net/cvs/?group_id=29749
Prilikom instalacije bitno je da u Delphi IDE dodate putanje do svih foldera u kojima se nalaze source fajlovi GLScene u Library path inace necete biti u mogucnosti da ih koristite. Kad to uradite u foderu DelphiX (gde je X verzija vaseg Delphia) cete naci pakete komponenti:
GLScene - komponente za rad sa 3D objektima
GLCg - komponente za rad sa Cg shaderima (morate imati instaliran NVidia Cg toolkit da bi mogli da instalirate ove komponente)*
GLSDL - rad sa SDL engineom (ova komponenta nije potrebna za rad sa GLScene i ja je licno nikad nisam koristio)*
GLSS_BASS - sound library BASS*
GLSS_FMOD - sound library FMOD*
GLS_ODE - physic engine ODE*
GLS_DWS - script engine Delph Web Script*
GLS_Python - script engine Python*
* Da bi ove komponente radile morate instalirati druge pakete. SDL, ODE, BASS, FMOD idu zajedno sa GLScene fajlovima. To su obicni Dll fajlovi koje je samo potrebno kopirati u Windows\System32 folder i to je to. DWS mozete skinuti sa http://www.dwscript.com/ Za Python jos ne znam gde mogu da ga pronadjem, ali se bez te komponente moze jer imate DWS Za detaljnija uputstva o instalaciji pogledajte homepage GLScene.
Kada je instalacija zavrsena dolazi na red i probanje komponenti (moj omiljeni deo ). Za pocetak cemo napraviti jednu loptu, svetlo i kameru koja gleda u loptu.
Prvo cemo komponentu GLScene sa GLScene grupe da postavimo na formu. Ta komponenta ce nam sluziti za kreiranje scene. Sledeca je na redu komponenta GLSceneViewer. Ona je zaduzena za iscrtavanje scene na nasoj formi. Ove dve komponente su skoro uvek obavezne. Sada postavimo GLSceneViewer1.Align na alClient tako da se GLSceneViewer1 rasiri preko cele forme.
Sada kliknite dva puta na GLScene komponentu (ili desni klik pa Show Scene Editor) i tako cete otviriti editor scene
Ovde cemo dodavati nase objekte.
Prvo sto cemo dodati je kamera. Desnim klikom na Cameras u Scene Editoru otvorice nam meni i tu kliknemo na Add camera. Kamera je dodata sada nam samo jos preostaje da u GLSceneVieweru postavimo Camera proerty na kameru koju smo sada kreirali. Klik na GLSceneViewer (nalazi se preko cele forme) i u Object Inspectoru pronadjemo property Camera i vrednost postavimo na GLCamera1. Ako ne postavimo kameru tada se na GLSceneVieweru nece nista videti pa... cim kreirate kameru odmah je postavide ovde
Sada dodajemo i nasu lopticu... desni klik na Scene Objects u Scene Editoru, zatim Add Object->Basic Geometry->Sphere. Lopta je dodata, ali se ne vidi!? Problem je sto se i lopta i kamera nalaze na koordinatama 0,0,0 pa kamera ne moze da vidi loptu. Sada cemo pomeriti loptu ispred kamere tako sto cemo postaviti Position property lopte na 0,0,-3. Sada se lopta vec vidi :)Primecujete da je lopta crna...
To je zato sto nismo nigde postavili svetlo! Da bi i to resili dodacemo i jedan izvor svetla. Desni na Scene Objects pa izaberite LightSource. Cim smo dodali svetlo lopta je osvetljena Po defaultu novo kreirani objekti su sivi i zbog toga je lopta siva.
To je u sustini princip rada GLScene... dakle dodajemo objekte u Scene Editoru, podesavamo im poziciju, velicinu, boju...
Kasnije cemo uraditi i primere u kojima cemo pomerati objekte po sceni, dodavati evekte, itd...
Za sad eksperimentisite malo sa osnovinm stvarima
Srecno!!!
[url=https://www.mycity.rs/must-login.png
Dopuna: 19 Jul 2005 16:18
Hello!!!
Kao sto rekoh sada cemo uraditi jos jedan jednostavan primer. I ovog puta pocinjemo stavljanjem GLScene i GLSceneViewer komponenti na formu. Sledece je na redu dodavanje kamere i postavljanje Camera property GLSceneViewera na nasu novo kreiranu kameru. Dodacemo i jedno svetlo kao u proslom primeru. Sledece na redu je dodavanje kocke. Kocka se dodaje kao i lopta. U Scene Editoru desni klik na Scene Objects->Add Object->Basic Geometry->Cube. Postavicemo poziciju kocke na 0, 0, -4. Sada cemo dodati i jednu loptu i nju postaviti na 0, 1.5, -4 tako da ce se videti iznad kocke kao na slici
Trenutno kocka i lopta nisu povezani... to cemo prikazati uskoro. Pre nego sto pocnemo da pomeramo objekte po sceni dodacemo jos jednu komponentu. Komponente se zove GLCadencer i nalazi se u GLScene grupi. Ova komponenta ima event koji se poziva prilikom svakog renderovanja. Znaci pre nego sto se scena iscrta izvrsi se nas event i tako svaki put. Sto se scena brze iscrtava to se nas event brze poziva. Tako cemo na brzim racunarima dobiti lepu, glatku animaciju, a na losijim nece sve biti usporeno nego ce jednostavno neki delovi animacije biti "preskoceni" (seckanje). Ova komponenta ima jedan lep property koji se zove Mode. Taj proerty odredjuje kad ce se nas event pozivati. Po defaultu stoji na ASAP (as soon as possible) sto nam daje najveci frame-rate, ali i 100% zuzeca procesora, zatim imamo ApplicationIdle i u tom modu se event pokrece samo kada aplikacija nema vise window poruka da obradjuje sto malo smanjuje frame-rate, ali i smanjuje opterecenje procesora. Na kraju imamo mod Manual i u tom modu GLCadencer nece pozivati event sve dok mi samo ne pozovemo GLCadencer.Progress. Ako neko bas jako zeli da sto manje opterecuje procesor postoji i property SleepLength. Dovoljno je postaviti ga na 1 i procenat zauzeca procesora ce drasticno pasti. Kada je SleepLength <> -1 tada GLCadencer u svojoj petlji poziva Sleep(SleepLength) cime prekida rad programa na odredjen broj milisekundi. Ja licno volim da imam sto vise frejmova u sekundi pa su mi default vrednosti sasvim ok.
Znaci postavili smo GLCadencer na formu i pre nego sto mozemo da ga koristimo treba da podesimo Scene property. Taj property odredjuje scenu za koju je nas GLCadencer zaduzen. Postavicemo ga na GLScene1. Sada nam ostaje da namisemo proceduru za OnProgress event.
procedure TForm1.GLCadencer1Progress(Sender: TObject; const deltaTime,
newTime: Double);
var
X: Single;
begin
X := Sin(newTime) * 2;
GLCube1.Position.SetPoint(X, 0, -4);
end;
OnProgress event nam osim standardnog Sender (ko je pozvao event) daje jos dva podatka, deltaTime i newTime. DeltaTime je vreme u sekundama izmedju proslog poziva OnProgress eventa i trenutnog, a NewTime je vreme u sekundama od prvog do trenutnog poziva ovog eventa ili jednostavno receno od kad je GLCadencer.Enabled postavljen na True do sad. U nasem slucaju pomeracemo kocku po X osi po obicnoj sinusnoj funkiciji u zavisnosti od vremena koliko je GLCadencer aktivan.
Sada pokrenite program i videcete kako kocka klizi levo desno dok lopta stoji nepomicna. Sada cemo postaviti loptu tako da bude joj pozicija zavisi od pozicije koscke. Otvorite Scene Editor, kliknite na loptu i prevucite je preko kocke. Trebalo bi da ih postavite ovako
Kad ste to uradili lopta se odjednom pomerila u nazad iako nismo menjali njenu poziciju.
To je zato sto sada property Position za loptu predstavlja poziciju lopte u odnosu na kocku. Posto se kocka nalazi na 0, 0, -4, a koordinate lopte u odnosu na kocku su 0, 0, -4 to nam govori da se lopta sada nalazi na 0, 0, -8 (pozicija kocke + pozicija lopte). Ako sada pokrenemo program videcemo da se i kocka i lopta pokrecu iako menjamo poziciju samo kocke. Ovo je vrlo korisno znati koristiti pa eksperimentisite malo
Toliko za danas!
[url=https://www.mycity.rs/must-login.png
Dopuna: 19 Jul 2005 16:21
Do sad su svi objekti koje smo kreirali bili sivi... sada cemo malo da im menjamo boje
Pocinjemo kao i uvek... GLScene, GLSceneViewer, Camera, LightSource (secate se da je objekat bio skroz crn bez svetla... zato nam je vrlo bitno da imamo svetlo na sceni ako hocemo da vidimo boje) i jedna lopta na koordinatama 0, 0, -4. Sad imamo scenu kao u prvom primeru (mnogo brze i lakse nego na pocetku, zar ne ).
Svaki objekat ima 4 vrste boje: Ambient, Diffuse, Emission i Specular.
Ambient i Diffuse se najcesce koriste. Kada postavimo svetlo na scenu ono svetli odredjenom bojom (koju mi definisemo).
Ambient vrednost je boja svetla koje se nalazi na celoj sceni... nije bitno da li je objekat obasjan izvorom svetlosti, da li je preblizu ili predaleko... ako je Ambient boja podesena na zeleno tada je cela scena obasjana zelenom bojom.
Diffuse svetlost je slicna kao Ambient samo sto zavisi od vrste svetlosnog izvora. Mi smo uvek samo postavljali LightSource bez promene parametara. Po defaultu svetlo je tipa Spot. Takvo svetlo je kao baterijska lampa... svetli u odredjenom smeru i sve sto je iza nje ili previse sa strane nije osvetljeno. Postoje jos dva tipa svetla. Omni... to je kao luster... svetli suda oko sebe... nema neki odredjen pravac. Parallel... hmmm... to je kao svetlost sa sunca... dolazi iz velike daljine i pod odredjenim uglom pada na sve objekte. Pravac i smer kod Parallel i Spot tipova svetla se definise u SpotDirection property.
Emission je boja svetlosti koja isijava iz objekta. Kad imate beli luster sa crvenom lampom i onda se vidi kao da je je i luster crven.
Specular je boja odsjaja na objektu. Kada je recimo bilijarska kugla jako izglancana onda se na njoj vidi odsjaj svetla.
Svi ovi svetlosni efekti mogu da se koriste zajedno. Jedino emission boja ne zavisi od izvora svetla dok sve ostale boje zavise. Ako je recimo diffuse boja svetla cisto crvena, a diffuse boja objekta cisto plava objekat ce izgledati crn jer nema ni mali delic svetla plave boje. Takva je situacija i sa ambient i specular bojama. Mozda sada sve zvuci malo konfuzno, ali ako budete malo ekperimentisali sa bojama sve ce vam biti jasno.
Jos jedna stvar... ambient i diffuse boja se u 99.99% slucajeva postavljaju na istu boju jer obe boje predstavljaju boju materijala objekta. Ambient vrednost svetla se postavi na neku tamno sivu tako da i ako svetlo nije upereno u objekat njegova boja se ipak malo nazire, a diffuse boja svetla se postavlja na cisto belu i objekti direktno ispred svetla se vide u svojoj prirodnoj boji.
Dosta pricanja... hajde da ofarbamo nasu lopticu
Posto nismo menjali poziciju svetla ono se nalazi na 0, 0, 0, a njen pravac koji takodje nismo dirali je 0, 0, -1. Posto se nas objekat nalazi na 0, 0, -4 on se nalazi ispred svetla i zato je obasjan. Hajde da mu promenimo boju u plavo.
Boja (i neke druge stvari) se definisu u Material property. Kliknite na '...' i otvorice se material editor.
Ovde imam dosta opcija. Na vrhu mozemo da biramo da li cemo podesavati boju za prednju stranu poligona ili za zadnju (uglavnom se zadnja strana poligona ne prikazuje pa nije ni bitno sta cete tu podesiti) i mozemo podesavati texturu za objekat. Texture cemo ostaviti za kasnije. Vidimo skale za podesavanje boja i uz pomoc njih cemo naterati nasu loptu da poplavi Imamo opciju da izaberemo kako ce se nas objekat iscrtavati (polygon mode). Po defaultu objekat se iscrtava kao puno telo, ali mozemo podesiti da se iscrtavaju samo ivice ili samo tacke koje definisu ivice (probajte sva tri moda i bice vam jasno sta koji radi). Zatim imamo Shininess klizac... ta osobina odredjuje koliko je objekad "izglancan" i koliki ce biti odsjaj specular boje. Poslednja opcija koja odredju kako ce objekat biti iscrtan je Blending mode... ako je mod postavljen na Opaque tada se objekat iscrtava svojom bojom i to je to. Ako je podesen na Transparency tada Alpha vrednost boja utice na providnost objekta, sto je Alpha manje to je objekat providniji. Additive mod iscrtava objekat tako sto se bojama objekta dodaju boje objekata koji su iza njega... ovaj mod morate isprobati da bi vam bilo malo jasnije sta se tu tacno desava.
Za sad hajde da podesimo ambient i diffuse boje objekta (front) na plavo. Kada kliknemo na Ok primeticete da se lopta obojila u plavo.
Vrlo jednostavno
Hajde da dodamo i emission i specular boje. Postavimo emission green komponentu na 200. Sada ce nas plavi objekat izgledati kao da nesto zeleno svetli iz njega. Sad cemo jos i da mu nabacimo crvenu "tufnu". Specular boju postavimo na cisto crvenu i da se lopta ne bi bas jako sjajila postavimo Shininess na 5. Kliknimo Ok i nasa lopta vise nije samo plava... Sva je nekako cudna
Experimentisite malo s bojama. Probajte da postavite neki drugi blending mode i da menjate alpha vrednost.
U sledecem primeru cemo pokazati kako se lako textura postavlja na objekat kao i koriscenje Material Library komponente.
[url=https://www.mycity.rs/must-login.png
Dopuna: 19 Jul 2005 16:31
Uglavnom nije bas najbolja ideja da se za za svaki objekat materijal (boja) postavlja kao sto sam objasnio u proslom primeru. Kada bi imali 1000 lopti koje treba da budu plave i ako bi za svaku postavili boju kao sto sam prosli put objasnio GLScene bi napravio 1000 materiala (za svaki objekat po jedan) koji su prakticno isti i prolikom renderovanja objekata bi svaki put menjao 1, 2, 3,... 1000 materijal bez potrebe sto bi dovelo do vrlo velikog usporenja programa. Da bi se to izbeglo postoji komponenta GLMaterialLibrary. Ona je vrlo korisna jer je u njoj moguce definisati JEDAN material koji ce posle koristiti neogranicen broj objekata. Nekom ce mozda ovo biti bezveze jer ako se promeni taj material svi objekti koji ga koriste ce takodje biti promenjeni, a nekom ce to biti prednost jer nece morati da menja boje svakom objektu posebno. Ovog puta cemo koristiti Material Library i necemo samo postavljati boju za objekte nego i texturu. Textura je slika koje je "nalepljena" na objekat da bi izgledao kao da je od drveta, plastike, metala ili nekog drugog materijala.
Za pocetak postavimo na formu GLScene, GLSceneViewer, GLCadencer i GLMaterialLibrary. Postavimo u sceni kameru (0, 0, 0), svetlo (0, 0, 0) i dve lopte (2, 0, -5) i (-2, 0, -5) ove lopte ce nam sluziti kao modeli. Ne zaboravite da GLSceneViewer1.Camera postavite na kameru koju smo kreirali i GLCadencer.Scene na GLScene1 (ovo vise necu da spominjem).
MaterialLibrary ima dva propertya koja su nam zanimljiva... to su Material i TextrePaths. TexturePaths su putanje po kojima ce MaterialLibrary traziti slike ako napisete naziv fajla bez putanje (npr. "Slika.jpg"). Property Material sadrzi sve materiale koji su kreirani. Hajde da kreiramo jedan material. Kliknite na '...' u Material property i otvorice vam se mali prozorcic u kojem mozete dodavati i brisati materiale.
Dodajmo jedan material pritiskom na Add New dugme. Sada u Object Inspectoru vidimo osobine materiala koji smo kreirali. Imammo Material (isto kao i Material property kod objekata... tu cemo definisati izgled materiala), Name (naziv materiala... uvek je dobra ideja da nazovete material kako bi kasnije mogli lakse da ga pronadjete), Shader (ovde mozemo definisati mali programcic kojice iscrtavati material... primeri su BumpShader (povrsina izgleda rapavo), CelShader (izgleda kao crtani film)...), Texture2Name (moguce je dve texture stopiti u jednu i time dobiti neki novi izgled... ovde se daje ime drugog materiala koji ce se koristiti za stapanje sa ovim), TextureOffset (ako je textura velika ili ako ne zelimo da uzmemo sliku od pocetka texture ovde mozemo podesiti koliko ce textura na materialu biti pomerena u odnosu na pravu texturu), TextureScale (ako zelimo da se textura ponovi vise puta na objektu ovde to definisemo).
Hajde da podesimo material i dodamo texturu. Klik na '...' u Material property. Otvara nam se vec poznat prozor
Postavimo Ambient i Diffuse boju na cisto belo i kliknimo na Texture kako bi smo dodali sliku. Sada na vidimo sledece:
Sada mozemo da izaberemo sliku koja ce biti na objektu... to radimo uz pomoc Image opcije. Izabracemo ovu sliku
http://www.geocities.com/srki_82/Tutorial/GLScene/Tut4Pic3.JPG
Ako se nekom vise svidja neka druga slobodno moze da je izabere.
Od opcija su nam na raspolaganju sledece stvari... ImageAlpha... svaka slika moze u sebi da sadrzi i alpha kanal cime odredjuje providnost objekta na koji je postavljena. Ako je ImageAlpha na Default koristi se alpha kanal iz slike. Ako je podesen na AlphaFromIntensity ili Luminance sto je slika svetlija manje se providi, a ako je postavljen na SuperBlackTransparency tada su sve crne povrsine providne.
Sledece opcije su Min i Mag filteri. GLScene kreira manje ili vece slicice od one koje smo mi dali ako je objekat mnogo manji ili veci od njenih dimenzija. Nacin na koji skuplja i siri sliku zavisi od ovih opcija. Uvek sam bio zadovoljan default vrednostima pa nisam mnogo zalazio u ostale mogucnosti, ali ako neko vidi da mu se textura mnogo zamuti moze da proba da postavi druge vrednosti.
Sledeca opcija nam je Texture Mode... ona odredjuje kako ce textura da se "stopi" sa bojama materijala. Decal i Replace jednostavno zanemaruju boju objekta i iscrtavaju samo texturu. Modulate promeni boju texture tako da "vuce" na boju koju smo definisali dok Blend racuna srednju vrednost izmedju definisane boje i boje texture. Mi cemo postaviti Texture mode na Modulate. Texture Warp odredjuje da li ce textura da se ponavlja ako je potrebno da prekrije ceo objekat (u obcijama moze da se izabere da li i u kojim pravcima da se dozvoli ponavljanje... po defaultu je da moze u svim pravcima).
Na kraju imamo checkbox Disabled koji odredjuje da li da se textura uopste vidi. Iskljucite taj checkbox i u preview cete videti nasu texturu
Kliknite na Ok. Jos jedna sitnica... u Name property upisacemo "Drvo". Eto... zavrsili smo nas material... sad da ga postavimo na loptice
Kao sto vidite... kliknite na mali plus pored Material property za loptu i u MaterialLibrary izaberite GLMaterialLibrary1 (komponenta koju smo stavili na formu i u kojoj su nasi materiajli). Zatim kliknite na '...' u LibMaterialName property i izaberite material "Drvo" i loptica vec lepse izgleda Sad to isto uradite i za drugu loptu.
Jedna vrlo bitna stvar!!!
Pre nego sto pokrenete program morate u Uses listu dodati unite koji omogucavaju ucitavanje slika koje smo koristili za texture. Za BMP slike nema potrebe nista da se dodaje dok za JPG treba da se doda JPEG unit, za TGA treba TGA unit...
Kada smo dodali JPEG u uses pokrecemo program i vidimo loptice
Da bi smo dokazali da obe lopte koriste isti material malo cemo se poigrati s njim. U GLCadencer cemo postaviti OnProgress event na
procedure TForm1.GLCadencer1Progress(Sender: TObject; const deltaTime,
newTime: Double);
var
C: Single;
begin
C := Sin(newTime) * 0.5 + 0.5;
with GLMaterialLibrary1.LibMaterialByName('Drvo') do
begin
Material.FrontProperties.Ambient.Red := C;
Material.FrontProperties.Diffuse.Red := C;
TextureScale.SetPoint(C, C, C);
end;
end;
Kao sto vidite menjamo material u MaterialLibrary i obe lopte menjaju svoju boju
Toliko za sada... ako budem imao vremena mozda napisem jos nesto za sad.
Vi slobodno experimentisite i posaljite kod ako napravite neki zanimljiv primer!
Poz!!!
[url=https://www.mycity.rs/must-login.png
Dopuna: 19 Jul 2005 16:38
Mogli bi smo umesto kocki i lopti da koristimo neki 3D model... bilo bi stvarno bezveze kad bi bili ograniceni samo na osnovne oblike. Ovog puta cemo napraviti mali programcic za pregled 3DS fajlova. 3DS su fajlovi koje pravi 3D Studio... oni u sebi sadrze podatke o izgledu objekta i podatke o materijalima. Sa GLScene je vrlo lako ucitavati 3D modele... GLScene ima podrsku za razne fajlove kao sto su 3DS, Quake 2 i 3 modele, HalfLife modele, OBJ fajlove, Quake nivoe... pa da pocnemo
Pacicemo na formu GLScene, GLSceneViewer, GLMaterialLibrary (ovde ce se ucitati materiali za 3d objekat), MainMenu (za meni za ucitavanje fajla) i OpenDialog. Na scenu cemo postaviti sledece stavke: kameru i svetlo (svetlo prevucite tako da mu kamera bude parent i da pozicija svetla zavisi od pozicije kamere... gde god da se nalazi kamera i svetlo ce ici za njom) i jedan FreeForm (Screen Objects->Add Object->Mesh Objects->FreeForm). FreeForm je objekat u koji ce biti ucitan nas 3DS fajl. Da bi GLScene znao gde da stavi materijale vezane za FreeForm moramo FreeForm.MaterialLibrary postaviti na GLMaterialLibrary1 koji smo vec stavili na formu. Jos malo i zavrsili smo. Postavicemo kameru na 0, 0, 200, a FreeForm ostaviti na 0, 0, 0. Uradicemo nesto sto nismo radili do sad... postavicemo GLCamera.TargetObject property na FreeForm1 sto ce naterati kameru da bude uvek okrenuta prema FreeForm objektu. Tako mozemo pomerati i FreeForm i kameru bez bojazni da cemo izgubiti objekat iz vida. Sada nista ne vidimo na formi jer 3DS fajl mozemo da ucitamo samo u runtimeu i zato cemo napraviti funkciju za ucitavanje. U MainMenu dodajte sledece stavke
Load 3DS file
-
Exit
Za Exit postavite da izadje iz programa (Application.Terminate), a za Load 3DS file napisite sledece
procedure TForm1.Load3DS1Click(Sender: TObject);
var
S: Single;
begin
if OpenDialog1.Execute then
begin
GLMaterialLibrary1.Materials.Clear;
GLFreeForm1.LoadFromFile(OpenDialog1.FileName);
S := 100 / GLFreeForm1.BoundingSphereRadiusUnscaled;
GLFreeForm1.Scale.SetVector(S, S, S);
GLFreeForm1.ResetRotations;
end;
end;
Kao sto vidite nema puno koda, a ovo radi ceo posao oko ucitavanja 3DS fajla
Prvo sto uradimo je praznjenje GLMaterialLibrarya jer je moguce da smo pre ovog vec ucitali neki objekat i ne bi zeleli da nam u ostanu stari materiali. Sledeca stvar koju radimo je ucitavanje fajla. Za to nam je potrebaj samo jedan red GLFreeForm1.LoadFromFile(OpenDialog1.FileName);. GLScene je toliko dobar da skoro sve uradi umesto nas. Posle ovog poziva u FreeForm se nalazi nas 3D objekat. Posto objekat moze da bude ogroman ili previse mali sledeca stvar koju radimo je postavljanje odgovarajuce velicine. GLFreeForm1.BoundingSphereRadiusUnscaled nam daje precnik lopte koja okruzuje ceo objekat i na osnovu nje cemo podesiti velicinu objekta da moze da stane u loptu precnika 100. Kamera ima DephOfView property. On odredjuje koliko daleko kamera moze da vidi. Po defaultu vrednost je 100, ali posto ce kraj naseg objekta biti dalje od 100 od nase kamere moracemo da povecamo ovu vrednost kako bi sve lepo videli. Stavicemo vrednost na 1000. Kada smo postavili odgovarajucu velicinu objekta ostaje nam jos samo da vratimo osnovni polozaj objekta (kasnije u kodu cemo moci da ga rotiramo). I to je to... u par redova koda mozemo da ucitamo bilo koji 3DS fajl.I jos jednom da napomenem... ako 3d objekat koristi neke slike osim BMP za texture moramo dodati unite koji ce "objasniti" Delphiu kako da ih ucita.
Sad nam ostaje jos da sredimo rotiranje objekta... to se takodje vrlo lako radi. Bice nam potrebne 2 globalne promenljive mX i mY pa ih dodajte. Obe su tipa Integer. U OnMouseMove eventu GLSceneViewera napisite sledece
procedure TForm1.GLSceneViewer1MouseMove(Sender: TObject;
Shift: TShiftState; X, Y: Integer);
begin
if ssLeft in Shift then
GLCamera1.RotateObject(GLFreeForm1, mY - Y, mX - X);
mY := Y;
mX := X;
end;
Zajedno sa kodom saljem i jedam mali 3DS fajl kako bi mogli da isprobate program. To je jedan cup... i primeticete da ima delova koji se "provide" bez razloga. To je zato sto u te "providne" delove gledamo s "pogresne strane". Secate se da smo mogli da zadajemo boje za Front i Back u Material Editoru... e pa ovi delovi koji se ne vide se ne vide zato sto ih gledamo sa Back strane. Po defaultu GLSceneViewer uopste ne prikazuje te Back strane. Da bi smo ga "naterali" da ih prikazuje moramo GLSceneViewer.Buffer.FaceCulling postaviti na False. Ako sada pokrenemo program videcemo da se sve lepo vidi
To je sve... mX i mY pamte poslednju poziciju misa kako bi znali za koliko treba da rotiramo objekat, a RotateObject sredjuje rotaciju. Prilicno jednostavno
Eto... u par linija koda imamo jednostavan viewer za 3ds fajlove. Sad vec znate mnogo vise nego sto sam ja znao kad sam poceo da radim sa GLScene
Pa... sta bi voleli da naucite sledece?
[url=https://www.mycity.rs/must-login.png
Dopuna: 19 Jul 2005 16:46
Ahhh... bas je lepo kada te puste ranije s posla Prosto uzivam... bazencic, pivce, muzika, lap-top... samo da ga ne ispustim u vodu Kao sto sam obecao red je da napravimo nasu prvu malu igru. Ovog puta cemo sve sto smo naucili da stavimo u jedan program i videcemo kako je moguce kreirati i brisati objekte na sceni u runtime.
Pocecemo tako sto cemo pobacati GLScene, GLSceneViewer, GLMaterialLibrary i GLCadencer na formu i kameru i svetlo na scenu. Sad dodajmo GLDummyCube na scenu 0, 0, -4 (Scene Objects->Add object->DummyCube) i nazovimo je Tabla. Ovaj objekat je prilicno koristan. Na sceni se vidi kao providna kocka cije su ivice iscrtane isprekidanom linijom, a kada se program pokrene onda se ne vidi. Neko se moze zapitati sta ce nam objekat koji se ne vidi... secate li se kada sam pokazao kako je moguce hijerarhijski postavljati objekte. E, DummyCube se koristi uglavnom za to. Ako postavimo nekoliko lopti, kocki ili bilo kojih objekata da njihove pozicije zavise od DummyCube, pomeranjem i rotiranjem DummyCube svi ti objekti ce se takodje kretati. U kodu cete videti malo bolje o cemu pricam.
Sada nam je cilj da napravimo plocicu koja ce se okretati. Treba da ima jednu stranu obojenu jednom dok su sve ostale obojene drugom bojom. Problem je sto GLCube to bas i ne moze da uradi... ali zato 2 GLCube mogu Dodajmo jednu kocku i postavimo je u DummyCube. Posto pozicija nase kocke sad zavisi od DummyCube znaci da ce se i nasa kocka naci na 0, 0, -4.
GLCube nam dozvoljava da izaberemo koje stranice kocke ce iscrtavati (Parts property) i mi cemo iskljuciti Back i tada strana koja je okrenuta od nas nije iscrtana. Sada cemo dodati jos jednu kocu u DummyCube i njoj cemo u Parts postaviti da iscrtava SAMO Back stranu tako da ce ona popuniti deo koji prva kocka nije iscrtala. I sada mozemo jednu stranu da obojimo u jednu, a ostale u drugu boju Samo postavimo materijale kocki na razlicite boje (recimo jedna strana na crveno, a ostale na plavo). Problem je sto sad ne mozemo da vidimo koje je boje deo okrenut od nas... zato cemo malo da zarotiramo nase kocke. Umesto da rotiramo jednu i drugu sve sto cemo uraditi jeste postavljanje ugla za DummyCube. Postavimo TurnAngle na 140 i sta vidimo... obe kocke su zarotirane i sada vidimo i zadnju stranu. Ovaj nacin cemo koristiti u igri da postavljamo i rotiramo polja.
Pa... hajde da pocnemo... obrisimo iz scene sve osim kamere, svetla i DummyCube (koju smo nazvali Tabla). Vratimo TurnAngle Table na 0. I spremni smo da pocnemo
Da bismo uopste mogli da igramo prvo moramo postaviti polja. Napravicemo nam jednu proceduru koja ce obrisati sva postojeca polja na Tabeli i postaviti nova. Proceduru cemo dodati recimo u public deo nase forme
type
TForm1 = class(TForm)
GLScene1: TGLScene;
GLSceneViewer1: TGLSceneViewer;
GLMaterialLibrary1: TGLMaterialLibrary;
GLCadencer1: TGLCadencer;
GLCamera1: TGLCamera;
GLLightSource1: TGLLightSource;
Tabla: TGLDummyCube;
private
{ Private declarations }
public
{ Public declarations }
procedure NovaIgra;
end;
Prva stvar koju cemo uraditi je brosanje postojecih polja. Posto ce sva polja biti u DummyCube koju smo nazvali Tabla mozemo ih obrisati sve pozivom samo jedne funkcije
Tabla.DeleteChildren;
Ovo ce obrisati sve objekte koji se nalaze u Tabla objektu. Da nismo koristili DummyCube morali bismo da cuvamo polja u nekom nizu pa da ih brisemo jedno po jedno dok ovako GLScene radi sve umesto nas.
Sledece sto treba da uradimo je da dodamo nova polja kao sto smo vec probali u designtime. Dodacemo u var deo procedure dve promenljive
var
Dummy: TGLDummyCube;
Cube: TGLCube;
One ce cuvati objkte koje budemo kreirali. Kad smo pravili polje prvo smo postavili DummyCube... to cemo uraditi i sad
Dummy := TGLDummyCube.CreateAsChild(Tabla);
Kada ovako kreiramo objekat on ce se nalaziti u objektu koji navedemo prilikom poziva CreateAsChild... znaci nas Dummy ce se nalaziti u objektu Tabla. Ako zelimo da kreiramo objekat koji nije vezan za neki drugi onda umesto CreateAsChild pozivamo samo Create.
Kad smo napravili Dummy treba da dodamo kocku koja ce iscrtavati sve sem Back strane. Da polje ne bi izgledalo previse "kockasto" malo cemo da spljostimo nasu "kocku". To bi izgledalo ovako
Cube := TGLCube.CreateAsChild(Dummy);
Cube.CubeDepth := 0.2;
Cube.Parts := Cube.Parts - [cpBack];
Ovaj deo svih polja ce biti iste boje pa bi bilo zgodno napraviti material u GLMaterialLibrary koji ce drzati boju za njih. Dodajmo jedan material proizvoljne boje i nazovimo ga "Pozadina". U designtime znamo kako se postavlja material objektima, a evo kako to ide u runtime
Cube.Material.MaterialLibrary := GLMaterialLibrary1;
Cube.Material.LibMaterialName := 'Pozadina';
Ostaje nam jos samo da dodamo i obojenu stranu. Posto cemo praviti 12 polja to je po 6 parova koji ce imati razlicitu boju pa hajde da dodamo jos 6 materijala razlicite boje u GLMaterialLibrary i nazovimo ih 0, 1, 2, 3, 4 i 5. I obojena strana je skoro gotova
Cube := TGLCube.CreateAsChild(Dummy);
Cube.CubeDepth := 0.2;
Cube.Parts := [cpBack];
Cube.Material.MaterialLibrary := GLMaterialLibrary1;
Cube.Material.LibMaterialName := '0';
To bi za sad bio deo koji inicijalizuje igru. Cela funkcija bi za sada izgledala ovako
procedure TForm1.NovaIgra;
var
X, Y: Integer;
Mat: array[0..11] of String;
Dummy: TGLDummyCube;
Cube: TGLCube;
// Izabira material za polje
function IzaberiMaterial: String;
var
I: Integer;
begin
I := Random(12 - (X + (Y * 4)));
Result := Mat[I];
Mat[I] := Mat[11 - (X + (Y * 4))];
end;
begin
// Brisemo sve objekte u Tabla
Tabla.DeleteChildren;
// Postavljamo boje za IzaberiMaterijal
for X := 0 to 5 do
begin
Mat[X] := IntToStr(X);
Mat[X + 6] := IntToStr(X);
end;
// Postavljamo plocice na tablu
for Y := 0 to 2 do
for X := 0 to 3 do
begin
// Dodajemo jedan DummyCube koji ce drzati
// pozadinu (kocku bez jedne strane) i
// zadnju stranu koja je obojena
Dummy := TGLDummyCube.CreateAsChild(Tabla);
Dummy.Position.SetPoint(-3 + X * 2, -1.5 + Y * 1.5, 0);
// Dodajemo pozadinu
Cube := TGLCube.CreateAsChild(Dummy);
Cube.CubeDepth := 0.2;
Cube.Parts := Cube.Parts - [cpBack];
Cube.Material.MaterialLibrary := GLMaterialLibrary1;
Cube.Material.LibMaterialName := 'Pozadina';
// Dodajemo obojenu stranu
Cube := TGLCube.CreateAsChild(Dummy);
Cube.CubeDepth := 0.2;
Cube.Parts := [cpBack];
Cube.Material.MaterialLibrary := GLMaterialLibrary1;
Cube.Material.LibMaterialName := IzaberiMaterijal;
end;
end;
Funkcija IzaberiMaterijal koristi Random da bi odredila boju polja... mogla je da se uradi i na drugi nacin. Ostaje nam da u Form.OnCreate podesimo da se ova procedura pozove i videcemo polja sa zadnje strane ako pokrenemo program
Sada... mogli bi da pocnemo da okrecemo plocice. Posto ce nam kasnije biti potrebno da znamo kad smo okrenuli dva polja dodacemo dve promenljive koje ce cuvati polja koja se okrecu i jos jednu promenljivu koja ce nam reci da li se polja okrecu u datom trenutku
var
Okretanje: Boolean;
Izabrana1, Izabrana2: TGLDummyCube;
Polje cemo da izaberemo u OnMouseDown eventu GLSceneViewera
procedure TForm1.GLSceneViewer1MouseDown(Sender: TObject;
Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
var
Obj: TGLCube;
begin
// Ako se nesto desava druge ploce ne mogu da se izaberu
if Okretanje then Exit;
Obj := TGLCube(GLSceneViewer1.Buffer.GetPickedObject(X, Y));
// Uzimamo u obzir samo kocke
if Obj <> nil then
begin
// Ako nismo izabrali ni jednu onda nam je ovo prva
// i pocinjemo sa okretanjem
if Izabrana1 = nil then
begin
// Parent od kocke koja je pozadina je DummyCube koja
// sadrzi i pozadinu i boju pa kada rotiramo
// DummyCube rotira se i pozadina i boja
Izabrana1 := TGLDummyCube(Obj.Parent);
Okretanje := True;
end
else
// Ako je prva vec izabrana pazimo da je nismo izabrali
// ponovo i ako nismo onda je izabrana i druga i
// pocinjemo sa okretanjem
if Izabrana1 <> Obj.Parent then
begin
Izabrana2 := TGLDummyCube(Obj.Parent);
Okretanje := True;
end;
end;
end;
Ovde nema niceg komplikovanog... kada kliknemo na neku kocku proveravamo da li je vec izabrana i ako nije uzimamo vrednost iz Parent propertya sto nam daje objekat u kojem se nasa kocka nalazi tj. DummyCube koji smo kreirali. Tako cemo u Izabrana1 ili Izabrana2 imati DummyCube koji treba da okrenemo da bi se polje videlo. Polje cemo okretati u OnProgress eventu GLCadencera
procedure TForm1.GLCadencer1Progress(Sender: TObject; const deltaTime,
newTime: Double);
begin
// Okrecemo izabrano polje
if Okretanje then
begin
// Vec smo izabrali drugo polje
if Izabrana2 <> nil then
begin
// Okrecemo ga
Izabrana2.TurnAngle := Izabrana2.TurnAngle + 500 * deltaTime;
// Okrenuo se na zeljenu stranu (ili mozda malo vise)
if Izabrana2.TurnAngle < 0 then
begin
// Resetujemo rotacije i postavljamo tacnu vrednost
// koju zelimo
Izabrana2.ResetRotations;
Izabrana2.Turn(180);
// Okretanje je zavrseno i pocinje pauza da igrac
// vidi sta je uradio
Okretanje := False;
// Ovde cemo proveriti da li su polja ista
end;
end
else
begin
// Okrecemo prvo polje
Izabrana1.TurnAngle := Izabrana1.TurnAngle + 500 * deltaTime;
if Izabrana1.TurnAngle < 0 then
begin
Izabrana1.ResetRotations;
Izabrana1.Turn(180);
Okretanje := False;
end;
end;
end;
end;
I ovde nema niceg komplikovanog mozete primetiti da sam vrednost sa kojom uvecavam ugao mnozio sa deltaTime. To je dobro zato sto ce i na racunaru koji ima 20 FPS i na onom koji ima 200 FPS rotacija da bude iste brzine. Pokrenimo program i probajmo da okrecemo polja.
Sada cemo da napravimo da igra malo zastane kada se okrenu dva polja, da proveri da li su ista i da ih vrati ako nisu. Za sad ce funkcija za proveravanje uvek govoriti da su polja razlicita da bi lakse objasnjavao kod. Dodacemo jos neke globalne promenljive
var
Pauza: Boolean;
Vracanje: Boolean;
Cekanje: Double;
Pauza je True ako smo u pauzi izmedju okretanja, Cekanje je vreme koji je ostalo do kraja pauze i Vracanje je True kada se polja vracaju u pocetnu poziciju. Pre nego sto pocnemo modifikovacemo pocetak dela koji nam vraca koja kocka je kliknuta i pocetak ce izgledati
if Okretanje or Pauza or Vracanje then Exit;
Tako igrac nece moci da okrece novo polje kad ne bi trebalo da moze.
Dodacemo proceduru Proveri u public deo nace forme i za sad napisati samo
procedure TForm1.Proveri;
begin
Vracanje := True;
end;
Malo cemo modifikovati i OnProgress event tako da reaguje na Vracanje i Pauzu
procedure TForm1.GLCadencer1Progress(Sender: TObject; const deltaTime,
newTime: Double);
begin
// Cekamo da istekne neko vreme
if Pauza then
begin
Cekanje := Cekanje - deltaTime;
if Cekanje < 0 then
Pauza := False;
end
else
// Vracamo polja ako su nisu ista
if Vracanje then
begin
// Okrecemo polja
Izabrana1.TurnAngle := Izabrana1.TurnAngle + 500 * deltaTime;
Izabrana2.TurnAngle := Izabrana1.TurnAngle + 500 * deltaTime;
// Ako se polje okrenulo skroz (ili mozda malo vise)
// resetujemo rotacije i vracanje je gotovo
if Izabrana1.TurnAngle < 0 then
begin
Izabrana1.ResetRotations;
Izabrana2.ResetRotations;
Izabrana1 := nil;
Izabrana2 := nil;
Vracanje := False;
end;
end
else
// Okrecemo izabrano polje
if Okretanje then
begin
// Vec smo izabrali drugo polje
if Izabrana2 <> nil then
begin
// Okrecemo ga
Izabrana2.TurnAngle := Izabrana2.TurnAngle + 500 * deltaTime;
// Okrenuo se na zeljenu stranu (ili mozda malo vise)
if Izabrana2.TurnAngle < 0 then
begin
// Resetujemo rotacije i postavljamo tacnu vrednost
// koju zelimo
Izabrana2.ResetRotations;
Izabrana2.Turn(180);
// Okretanje je zavrseno i pocinje pauza da igrac
// vidi sta je uradio
Okretanje := False;
Pauza := True;
Cekanje := 0.5;
// Proveravamo da li su polja ista
Proveri;
end;
end
else
begin
// Okrecemo prvo polje
Izabrana1.TurnAngle := Izabrana1.TurnAngle + 500 * deltaTime;
if Izabrana1.TurnAngle < 0 then
begin
Izabrana1.ResetRotations;
Izabrana1.Turn(180);
Okretanje := False;
end;
end;
end;
end;
Sve je sasvim jasno ovde... posle Vracanja podesavamo izabrana polja na nil tako da ponovo mozemo bez problema da biramo i prvo i drugo polje. Krenimo igru sada... skoro kao da je gotova... ostalo nam je jos samo saznamo da li su okrenuta polja ista i da ih sakrijemo ako jesu. Najlakse nam je da samo uporedimo materijale obojene strane. Dodacemo jos jednu globalnu promenljivu koja ce nam signalizirati ako treba da sakrijemo polja
var
Nestajanje: Boolean;
I sada ce nasa Proveri procedura izgledati ovako
procedure TForm1.Proveri;
begin
// Ako su boje iste vreme je za "nestajanje" :)
Nestajanje :=
TGLCube(Izabrana1.Children[1]).Material.LibMaterialName =
TGLCube(Izabrana2.Children[1]).Material.LibMaterialName;
// Ako nisu ista onda ih vracamo
Vracanje := not Nestajanje;
end;
Koristili smo property Izabrana1.Children. Ona nam vraca objekte koji se nalaze u Izabrana1. U nasem slucaju Izabrana1 je DummyCube koji sadrzi dve kocke. Prvu (index = 0) koja je okvir za polje i drugu (index = 1) koja je obojena strana. Na taj nacin mozemo doci do materijala obojene strane.
Ostalo nam je jos samo da sredimo OnProgress event da reaguje na Nestajanje
procedure TForm1.GLCadencer1Progress(Sender: TObject; const deltaTime,
newTime: Double);
begin
// Cekamo da istekne neko vreme
if Pauza then
begin
Cekanje := Cekanje - deltaTime;
if Cekanje < 0 then
Pauza := False;
end
else
// Vracamo polja ako su nisu ista
if Vracanje then
begin
// Okrecemo polja
Izabrana1.TurnAngle := Izabrana1.TurnAngle + 500 * deltaTime;
Izabrana2.TurnAngle := Izabrana1.TurnAngle + 500 * deltaTime;
// Ako se polje okrenulo skroz (ili mozda malo vise)
// resetujemo rotacije i vracanje je gotovo
if Izabrana1.TurnAngle < 0 then
begin
Izabrana1.ResetRotations;
Izabrana2.ResetRotations;
Izabrana1 := nil;
Izabrana2 := nil;
Vracanje := False;
end;
end
else
// Sklanjamo polja sa table ako su ista
if Nestajanje then
begin
Izabrana1.Free;
Izabrana2.Free;
Izabrana1 := nil;
Izabrana2 := nil;
// Nema vise polja... nova igra!?
if Tabla.Count = 0 then
if Application.MessageBox('Nova igra?', 'Info', MB_YESNO) = ID_YES then
NovaIgra
else
Application.Terminate;
end
else
// Okrecemo izabrano polje
if Okretanje then
begin
// Vec smo izabrali drugo polje
if Izabrana2 <> nil then
begin
// Okrecemo ga
Izabrana2.TurnAngle := Izabrana2.TurnAngle + 500 * deltaTime;
// Okrenuo se na zeljenu stranu (ili mozda malo vise)
if Izabrana2.TurnAngle < 0 then
begin
// Resetujemo rotacije i postavljamo tacnu vrednost
// koju zelimo
Izabrana2.ResetRotations;
Izabrana2.Turn(180);
// Okretanje je zavrseno i pocinje pauza da igrac
// vidi sta je uradio
Okretanje := False;
Pauza := True;
Cekanje := 0.5;
// Proveravamo da li su polja ista
Proveri;
end;
end
else
begin
// Okrecemo prvo polje
Izabrana1.TurnAngle := Izabrana1.TurnAngle + 500 * deltaTime;
if Izabrana1.TurnAngle < 0 then
begin
Izabrana1.ResetRotations;
Izabrana1.Turn(180);
Okretanje := False;
end;
end;
end;
end;
To je to
Kada je potrebno da polje nestane mi ga samo unistimo i vise ga nema. Na kraju proverimo da li smo unistili sva polja i ako jesmo pitamo igraca da li zeli da igra ponovo.
Bez komplikovanih stvari moze da se napravi nesto zanimljivo.
U sledecem postu cemo malo promenuti kod pa ce polja polako da postaju sve providnija umesto sto samo odjednom nestanu.
Dopuna: 19 Jul 2005 16:52
I za kraj ove igre sacuvali smo "nestajanje" polja. Nestajanje cemo izvesti tako sto cemo alpha vrednos materiala polako smanjivati dok materijal ne postane potpuno providan. Da bi alpha vrednos uopste menjala providnost materiala moramo Blend mode postaviti na Transparency i zato postavimo to za sve materiale koje smo definisali osim za material Pozadina. Problem bi bio ako bismo menjali material Pozadina sva polja bi se menjala jer smo pri kreiranju kocku koja crta okvir polja povezali sa Pozadina materijalom. Zato cemo kreirati jos jedan material "FadeOut" i napraviti ga isto kao i Pozadina osim sto ce FadeOut imati Blend mode = Transparency. Dodacemo jos dve globalne promenljive u kojima cemo cuvati materijale koje menjamo
var
MatBoja, MatFade: TGLMaterial;
MatFade mozemo postaviti na "FadeOut" material prilikom kreiranja forme
procedure TForm1.FormCreate(Sender: TObject);
begin
Randomize;
// Postavlja polja na tablu
NovaIgra;
// Uzima material za "nestajanje" polja
MatFade := GLMaterialLibrary1.LibMaterialByName('FadeOut').Material;
end;
Materijal boje koja treba da nestane mozemo uzeti u funkciji Proveri
procedure TForm1.Proveri;
begin
// Ako su boje iste vreme je za "nestajanje" :)
Nestajanje :=
TGLCube(Izabrana1.Children[1]).Material.LibMaterialName =
TGLCube(Izabrana2.Children[1]).Material.LibMaterialName;
// Ako nisu ista onda ih vracamo
Vracanje := not Nestajanje;
if Nestajanje then
begin
// Postavljamo material za nestajanje
TGLCube(Izabrana1.Children[0]).Material.LibMaterialName := 'FadeOut';
TGLCube(Izabrana2.Children[0]).Material.LibMaterialName := 'FadeOut';
// Uzimamo materijal za boju kako bismo mogli
// polako da ga napraimo providnim
MatBoja := GLMaterialLibrary1.LibMaterialByName(
TGLCube(Izabrana1.Children[1]).Material.LibMaterialName).Material;
end;
end;
Kao sto vidite u proceduri proveri takodje postavljamo material FadeOut za okvire polja koje treba da nestanu. Tako cemo moci samo njih da menjamo.
Sada cemo jos samo da izmenimo deo OnProgress eventa za Nestajanje
if Nestajanje then
begin
// Smanjujemo alpha vrednost tako da pozadina postaje sve
// providnija
MatFade.FrontProperties.Diffuse.Alpha :=
MatFade.FrontProperties.Diffuse.Alpha - 1 * deltaTime;
// Smanjujemo alpha vrednost tako da boja postaje sve
// providnija
MatBoja.FrontProperties.Diffuse.Alpha :=
MatBoja.FrontProperties.Diffuse.Alpha - 1 * deltaTime;
// Malo da vrtimo polja dok nestaju ;)
Izabrana1.Turn(1000 * deltaTime);
Izabrana2.Turn(1000 * deltaTime);
// Ako je sve nevidnjivo brisemo polja
if MatFade.FrontProperties.Diffuse.Alpha <= 0 then
begin
Izabrana1.Free;
Izabrana2.Free;
Izabrana1 := nil;
Izabrana2 := nil;
// Vracamo ponovo alpha na 1
MatFade.FrontProperties.Diffuse.Alpha := 1;
MatBoja.FrontProperties.Diffuse.Alpha := 1;
Nestajanje := False;
// Nema vise polja... nova igra!?
if Tabla.Count = 0 then
if Application.MessageBox('Nova igra?', 'Info', MB_YESNO) = ID_YES then
NovaIgra
else
Application.Terminate;
end;
end;
Znaci sve sto radimo je polako zmanjivanje alpha vrednosti boje materijala i nase polje ce polako da nestaje. Dodao sam i malo rotiranja kako bi sve bilo zanimljivije
Kada objekat skroz nestane (alpha <= 0) brisemo ga i vracamo alpha vrednos materijala za nestajanje ponovo na 1 kako bi bio spreman za sledece nestajanje.
I to je sve za ovu igru.
Mozete dodati da se meri vreme za koje je igra predjena, broj okretanja, highscore tabelu, izbor slika za polja (polja mogu da imaju texture)... slobodno experimentisite
Sledece sto nas ceka su "ponasanja" objekata... teracemo objekat da se krece po nekoj putanji, vrtecemo tocak na osovini... videcu sta ce mi sve pasti na pamet
[url=https://www.mycity.rs/must-login.png
Dopuna: 19 Jul 2005 16:59
Posle zanimljive igre vracamo se dosadnim sitnicama Svaki objekta moze da ima asocirane efekte i osobine koje opisuju kako ce se ponasati na sceni. I efekti i osobine zahtevaju GLCadencer jer je on zaduzen za update. Sada cemo se pozabaviti osobinom Simple Inertia. Ova osobina nam dozvoljava da zadamo ugaonu brzinu (po x, y ili z osi objekta) ili brzinu kretanja u nekom pravcu i otpor koji ce na kraju zaustaviti kretanje. Potrebno je samo da podesimo te podatke i nas objekat ce poceti da se krece ili rotira (ili i jedno i drugo) i na kraju ce se zaustaviti. U ovom primeru cemo postaviti 2 cilindra (jedan ce biti osovina, a drugi tocak) i pritiskom na gore cemo dati gas (tocak ce se vrteti u napred), na dole cemo ici u nazad i na space cemo pritisnuti kocnicu. Pocnimo postavljanjem GLScene, GLSceneViewera i GLCadencera. Dodajmo kameru i svetlo, a zatim 2 cilindra. Prvi postavimo na 0, 0, -4. Postavimo TopRadius i BottomRadius na 0.1 da bi malo stanjili osovinu i na kraju postavimo RollAngle na 90 kako bismo je polozili. Drugi cilindar postavimo na 2, 0, -4. Postavimo RollAngle na 90, BottomRadius i TopRadius na 1, Height na 0.1 i Slices na 7. Tako cemo dobiti tocak sa desne strane. Postavili smo Slices na mali broj da bi lakse uocili kako se tocak okrece.
Sad cemo dodati osobinu nasem objektu. Kliknimo desnim na drugi cilindar (onaj koji nam predstavlja tocak) i izaberimo Add behaviour->Simple Intertia. Da bismo videli koje sve osobine ima nas objekat moramo kliknuti Show Behaviours/Effects dugme na vrhu Scene Editora.
Sada mozemo da kliknemo na osobinu koju smo dodali i da vidimo sta sve mozemo da podesimo.
DampingEnable - da li da otpor zaustavlja kretanje (ako pravimo planetu koja se neprestano okrece mozemo ovo iskljuciti)
Mass - masa objekta od koje zavisi kojom brzinom ce se zaustaviti
Name - ime osobine (kasnije je mozemo pronaci na osnovu imena ako je potrebno)
Pitch, Roll i Turn speed - brzine okretanja objekta oko osa
Rotation Damping - otpor prilikom okretanja
Translation Speed - brzina kretanja po x, y i z osi
Translation Damping - otpor prilikom kretanja
Otpor moze biti konstantan, linearan i kvadratni. Kada je konstantan onda se brzina dok je veca ili manja od nule priblizava nuli konstantnom brzinom u zavisnosti od mase.
Ako je otpor linearan sto je brzina veca veci je i otpor. Odnos izmedju brzine i otpora je linearan.
Ako je otpor kvadratni sto je brzina veca veci je i otpor, ali je ovog puta odnos izmedju brzine i otpora je kvadratni (otpor je vec za vece brzine nego kad je otpor linearan).
Za sad necemo menjati ovde nista jer cemo vrednosti postavljatiu runtime u zavisnosti od pritisnutih tastera.
Trebace nam Keyboard unit pa ga ubacite u uses listu. Kada se koriste osobine moramo dodati i GLBehaviours unit inace nas program nece raditi.
Postavimo sad OnProgress event
procedure TForm1.GLCadencer1Progress(Sender: TObject; const deltaTime,
newTime: Double);
var
I: TGLBInertia;
begin
I := GetOrCreateInertia(GLCylinder2);
if IsKeyDown(VK_UP) and (I.TurnSpeed < 1000) then
begin
I.TurnSpeed := I.TurnSpeed + 300 * deltaTime;
end;
if IsKeyDown(VK_DOWN) and (I.TurnSpeed > -500) then
begin
I.TurnSpeed := I.TurnSpeed - 100 * deltaTime;
end;
if IsKeyDown(' ') then
I.RotationDamping.Constant := 1000
else
I.RotationDamping.Constant := 50;
end;
Funkcija GetOrCreateInertia proverava osobine objekta i kada naidje na Simple Inertia vraca nam je ili ako ta osobina ne postoji kreira je. Kao sto vidite nije bilo potrebno da kreiramo Simple Inertia u Scene Editoru jer bi nam GLScene kreirao tu osobinu kad bi je zatrazili, ali nije na odmet da znamo kako se osobine dodaju i u designtime
Promenljiva I je tipa TGLBInertia koja sadrzi podatke o Simple Inertia osobini. Ostatak koda je prilicno jasan.
Kada smo pritisnuli gore i brzina je manja od 1000 povecavamo brzinu okretanja. Slicno vazi i kada pritisnemo dole.
Kada pritisnemo space povecavamo otpor (pritiskanje kocnice), a ako space nije pritisnut otpor stavljamo na malu vrednost kako bi se tocak zaustavio posle nekog vremena ako ne "dajemo gas"
To je to... probajte da experimentisete malo... probajte da radite i sa Translation Speed...
[url=https://www.mycity.rs/must-login.png
Dopuna: 19 Jul 2005 17:04
Ovaj tutorial je nisam napisao ja. Napisao ga je Jovan Prokopović
Do sada smo koristili gotove objekte (Cube, Sphere ...) i ucitavali smo objekte napravljene u nekom 3D programu, ali nakad moze da nam zatreba da kreiramo objekt u toku izvrsavanja aplikacije (u zavisnosti od proracuna, akcija korisnika ...).
Zato u GLScene postoji nekoliko klasa koje nam to omogucavaju.
Sada cemo da napravimo mali program u kome kreiramo objekte koji nastaju revolucijom (rotacijom linije) oko jedne ose.
Na formu dodajte GLScene, GLSceneViewer, Camera, LightSource,
kameru postavite na (0,0,10) i jedan RevolutionSolid (Screen Objects>Add Object>Advanced geometry>RevolutionSolid).
Dodacemo jedan taster i jos dva editbox-a,
U OnClick tastera dodajemo kod cij je zadatak da dota nod (tacku) linije koju rotiramo.
procedure TForm1.Button1Click(Sender: TObject);
begin
GLRevolutionSolid1.AddNode(StrToFloat(Edit1.Text), StrToFloat(Edit2.Text),0);
end;
Kao Sto vidite vrlo jednostavno, Edit1 je X kordinata, Edit2 je Y kordinata, linija se rotira oko Y ose.
Sad pokrenite program i dodajte nekoliko nodova (naprimer (0,3), (2,2), (1,1), (2,0) ...), trebalo bi da vidite neki objekt.
Dodacemo i kretanje kamere oko objekta, postavicemo GLCamera.TargetObject property na GLRevolutionSolid1, devinisemo dve globalne promenljive mX i mY i dodamo ovaj kod.
procedure TForm1.GLSceneViewer1MouseDown(Sender: TObject;
Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
mX:=X; mY:=Y;
end;
procedure TForm1.GLSceneViewer1MouseMove(Sender: TObject;
Shift: TShiftState; X, Y: Integer);
begin
If ssLeft in Shift then
GLCamera1.MoveAroundTarget(mY-Y, mX-X);
mX:=X; mY:=Y;
end;
Sad kad pokrenemo program dodamo nekoliko nodova imamo objekt oko kog moze da kruzi kamera (znaci ne rotiramo sam objekt kao u jedno od ranijih primera).
Ali objek i nije nesto narocito lep sve linije su prave (nije zaobljen), zato cemo dodati je jedan CheckBox i ovaj kod
procedure TForm1.CheckBox1Click(Sender: TObject);
begin
If CheckBox1.Checked then GLRevolutionSolid1.SplineMode:=lsmBezierSpline
else GLRevolutionSolid1.SplineMode:=lsmLines;
end;
Sad imamo lepo zaobljen objek kad cekiramo checkbox.
Dodacemo jos dva ScrollBara, Position prvog ScrollBara postavite na 10, a drugog na 16, i jos malo koda
procedure TForm1.ScrollBar1Change(Sender: TObject);
begin
GLRevolutionSolid1.Division:=ScrollBar1.Position;
end;
procedure TForm1.ScrollBar2Change(Sender: TObject);
begin
GLRevolutionSolid1.Slices:=ScrollBar2.Position;
end;
Division predstavlja broj segmenata linije izmedju dva noda (prilikom zaobljavanja), a Slices broj koraka prilikom rotiranja linije.
To je uglavnom to, GLRevolutionSolid ima jos nekoliko osobina ali to ostavljam vama da isprobate.
[url=https://www.mycity.rs/must-login.png
Dopuna: 19 Jul 2005 17:06
Posle male pauzice nastavljamo sa primerima.
Pokazacemo kako se koristi Movement controls osobina (u designtime i u runtime) kao i PointTo funkciju objekata u GLScene.
Postavimo scenu (ne zaboravite i GLCadencer), na njoj kameru i svetlo, a od objekata (Basic Geometry) GLIcosahedron (ovom objektu cemo kretanje praviti u designtime), GLDodecahedron (ovom u runtime) i (Advanced Geometry) GLArrowLine (to je samo strelica i prilicno je korisna za pokazivanje u nesto... sa njom cemo koristiti PointTo funkciju).
Posto cemo koristiti osobine objekata moram u uses ubaciti GLBehaviours unit, GLMovement jer cemo koristiti Movement controls i u runtime kao i VectorGeometry da bismo lakse postavljali vektore u runtime. Postavimo objekte na sledece pozicije GLArrowLine 0, 0, -4, a GLIcosahedron i GLDodecahedron na 0, 0, -8. Njihove pozicije i nisu mnogo bitne jer ce Movement controls da ih pomeraju, ali cisto da ih vidimo da su i oni na sceni. Kad smo ovo odradili mozemo da krenemo na nov deo.
Kliknimo desnim na GLIcosahedron i izaberimo Add behaviour->Movement controls. Izaberimo Movement controls osobinu u Scene Editoru i u Object Inspectoru mozemo da pravimo putanje za nas objekat. Moguce je spremiti vise putanja i u progrmu birati koja ce da se izvrsava. Mi cemo koristiti samo jednu, a ako nekom bude previse komplikovano da shvati kako se biraju putanje (hint: ActivePath) neka pita :)Putanja se kreira tako sto zadajemo tacke u prostoru i definisemo koliko ce objekat sa se zarotira i/ili promeni velicinu dok putuje. Dodacemo novu putanju pritiskom na '...' u Paths property i biranjem Add new u prozorcicu koji se otvorio. Sada nam preostaje da dodajemo tackice kroz koje ce objekat prolaziti (uz rotiranje i promenu velicine). Tacke dodajemo na isti nacin kao i putanje i nalaze se u Nodes property. Dodacemo sledece tacke:
Pozicija (X, Y, Z): 1, -2, -8
Rotacija (Pitch, Roll, Turn): 50, 0, 0
Scale (X, Y, Z): 1, 1, 1
Speed: 2
Pozicija (X, Y, Z): 3, 0, -8
Rotacija (Pitch, Roll, Turn): 50, 50, 0
Scale (X, Y, Z): 1, 1, 1
Speed: 2
Pozicija (X, Y, Z): 4, 1, -8
Rotacija (Pitch, Roll, Turn): 50, 50, 50
Scale (X, Y, Z): 1, 1, 1
Speed: 2
Pozicija (X, Y, Z): 2, 2, -8
Rotacija (Pitch, Roll, Turn): 0, 50, 50
Scale (X, Y, Z): 1, 1, 1
Speed: 2
Pozicija (X, Y, Z): -4, -3, -8
Rotacija (Pitch, Roll, Turn): 0, 0, 50
Scale (X, Y, Z): 1, 1, 1
Speed: 2
Pozicija (X, Y, Z): 0, 0, -8
Rotacija (Pitch, Roll, Turn): 0, 0, 0
Scale (X, Y, Z): 1, 1, 1
Speed: 2
To ce nam biti neko kretanje za nas prvi objekat. Bilo bi lepo da vidimo kako ce da se on krece, zar ne? Da bi smo izabrali aktivnu putanju u designtime postavicemo ActivePathIndex property Movement controls osobine na 0 sto bi znacilo da smo izabrali prvu putanju. Ostaje nam jos da u OnCreate eventu nase forme pokrenemo nas objekta, a to cemo uraditi ovako
procedure TForm1.FormCreate(Sender: TObject);
begin
GetOrCreateMovement(GLIcosahedron1).StartPathTravel;
end;
Ako pokrenemo program nas objekat ce se kretati. Prvo sto upada u oci je da se objekat ne krece uvek konstantnom brzinom iako smo Speed property svake tacke postavili na 2! To je trenutno jedan od bugova u GLScene, ali ako se tacke lepo i dovoljno blizu postave ovaj bag se skoro ne primecuje. Posto ne zelimo da se nas objekat zaustavi posle par sekundi kretanja postavicemo Looped property putanje na True. Da bi looped putanja lepo izgledala pocetna i krajnja tacka bi trebale da budu iste pa cemo dodati jos jednu tacku na putanji koja je ista kao i prva. Sada nas prvi objekat nekako nezgrapno uspeva da se krece po sceni
Sad je red da to uradimo i sa drugim objektom, ali u runtime. Tacke cemo dodati u OnCreate eventu forme... event ce izgledati ovako:
procedure TForm1.FormCreate(Sender: TObject);
var I: Integer;
begin
Randomize;
GetOrCreateMovement(GLIcosahedron1).StartPathTravel;
with GetOrCreateMovement(GLDodecahedron1) do
begin
with Paths.Add do
begin
for I := 0 to 19 do
begin
with Nodes.Add do
begin
PositionAsVector := VectorMake(Random(10) - 5,
Random(8) - 4,
Random(3) - 8);
RollAngle:= Random(360);
PitchAngle := Random(360);
TurnAngle := Random(360);
ScaleAsVector :=VectorMake(1 + Random,
1 + Random,
1 + Random);
Speed := Random(4) + 1;
end;
Nodes.Add.Assign(Nodes[0]);
Looped := True;
end;
end;
ActivePathIndex := 0;
StartPathTravel;
end;
end;
GetOrCreateMovement kreira Movement controls za nas objekat i vraca nam ga. Zatim sa Paths.Add dodajemo novu putanju i sa Nodes.Add nove tackice. Postavljamo njihove podatke i na kraju dodajemo jos jednu tacku koja je ista kao i prva. Postavljamo Looped na True kako bi se putanja pokrenula ponovo kad joj dodje kraj. Sve sto nam je preostalo je da postavimo aktivnu putanju i da pokrenemo objekat. Prosto k'o pasulj
Hajde jos da sredimo i da strelica pokazuje na objekat ciju putanju kreiramo u runtime. Za to je dovoljna samo jedna linija u GLCadenceru
procedure TForm1.GLCadencer1Progress(Sender: TObject; const deltaTime,
newTime: Double);
begin
GLArrowLine1.PointTo(GLDodecahedron1, YHmgVector);
end;
Sve sto kazemo je objekat na koji zelimo da linija pokazuje i gde joj je "gore" (YHmgVector ima vrednost 0, 1, 0).
To je to za sad... sledece sto nas ceka su Time Events... sa ovom komponentom mozemo da u odredjeno vreme uradimo nesto sa objektima ili bilo cim. Moze biti prilicno korisna stvarcica za animacije u igri.
Bye!!!
[url=https://www.mycity.rs/must-login.png
Dopuna: 19 Jul 2005 17:08
Izgleda forum ne dozvoljava duzi post... neka neko nesto napise pa da mogu da nastavim
|