Múltkor ott hagytuk abba, hogy sikerült egy szép sínes háromszöget kirajzolnunk a képernyőre. A kezdeti öröm mára már biztos elmúlott, így ideje továbblépnünk. Ehhez viszont újabb fogalmakkal kell megismerkednünk. Kezdjünk is hozzá.
A viewport definiálása
A viewport az az ablakon belüli rész, ahová rajzolunk, tehát a viewport transzformációval adjuk meg a létrejövő kép méretét. A viewport általában maga az ablak, de elképzelhető az is, hogy a viewport az ablaknak csupán egy része. A következő két ábra közül az egyik olyan viewportot ábrázol, amely az egész ablakot lefedi, a másiknál a viewport a létrehozott ablak bal alsó sarkánál helyezkedik el:
Az aktuális viewportot a:
void glViewport (int x , int y , GLsizei width , GLsizei height);
eljárással specifikálhatjuk. Az eljárás egy téglalapot definiál az OpenGL ablakba, ahová rajzolni szeretnénk. Az (x, y) paraméterek specifikálják a viewport bal alsó sarkát, width és height pedig a viewport téglalap méretét. Alapértelmezésben a paraméterek a (0, 0, winWidth, winHeight) értékeket veszik fel, ahol winWidth és winHeight az ablak méretei. pl.: glViewport(0, 0, w, h) esetén ha az ablak szélessége w, magassága pedig h, akkor a viewport az ablak lesz.
Vetítési mátrixok
Ahhoz, hogy kockát tudjunk rajzolni, hogy szépen látszódjon vetítést kell megadni. Erre az OpenGL-ben kétfajta lehetőség van: a merőleges és a centrális vetítés. Itt némi kiegészítésre van szükség a vetítésekkel kapcsolatosan: a két alapvető vetítési fajtán belül még igen sokféle különböző vetítést meg lehet adni; perspektív vetítésnél a vetítéseket az elsődleges távlatpontok száma szerint osztályozzuk, párhuzamos vetítés esetén pedig a vetítési irány és a vetítési sík egymáshoz való viszonya szerint. A vetítéseknek az a lényege, hogy a teret síkra képezik le (a képernyőre). Egy vetítés beállításához meg kell adni egy térrészt, amit a képernyőre képez (az ezen kívül eső részt a rendszer egyszerűen levágja). Ez merőleges vetítésnél egy téglatest párhuzamos vetítésnél csonka gúla. Alapértelmezés szerint merőleges vetítés van és a már említett origó középpontú 2x2x2-es kocka az a térrész, amit leképez. Merőleges vetítésnél úgy képez a rendszer, hogy a távolság nem érzékelhető, tehát egyszerűen elhagyja a mélységi (z) koordinátáját, majd a képernyőre méretezi a tartományt. Ez a vetítés általában a szerkesztőprogramokban hasznos, meg, ha csak egyszerű 2D-s dolgokat szeretnénk rajzolni. Ebből már sejthető is, hogy mi többnyire nem ezt fogjuk használni. A centrális vetítésnél már érzékelhető a távolság: a közeli dolgok nagyobbak a távoliak kisebbek. Ebből következik, hogy a távolabbi dogokból több fér egy képernyőre, mint közelikből. Sőt, ha a szemet egy pontnak vesszük, akkor, ha közvetlen a szem elé rajzolunk egy pontot, az óriásinak tűnhet (akár az egész képet kitakarhatja). Ezért kell megadni egy közeli vágósíkot, aminél közelebbi dolgok már nem látszanak. A merőleges és a centrális vetítés megadására az alábbi függvények szolgálnak:
- centrális - gluPerspective()
- merőleges - glOrtho()
void glOrtho(double left, double right, double bottom, double top, double near, double far);
eljárással a párhuzamos vetítés látóterét specifikálhatjuk.
A left és right adják meg a baloldai és jobboldali függőleges vágósíkok koordinátáit. A bottom és top az alsó és felső vízszintes vágósíkok koordinátái. A near és far adják meg a közeli és távoli vágósíkok távolságát a szemtől. A (left, bottom, -near) és a (right, top, -near) specifikálják tehát a közeli vágósík pontjait, amelyek ráfeszülnek az ablak bal alsó és jobb felső sarkaira ( feltételezve, hogy a szem a (0, 0, 0) pontban van). A far adja meg a távoli vágósík távolságát a szemtől. Tehát a közeli vágósík ablakba eső részének bal alsó sarka: (left, bottom, -near), a jobb felső sarka: (right, top, -near). A távoli vágósík ablakba eső részének bal alsó sarka: (left, bottom, far), jobb felső sarka: (right, top, far). Ha kétdimenziós objektumokat akarunk rajzolni, akkor a
void gluOrtho2D(double left , double right, double bottom, double top);
eljárással is specifikálhatjuk a vetítési mátrixot. Ekkor a vágási téglalap egyszerűen a (left, bottom, right, top) koordinátákkal megadott téglalap. A glOrtho / gluOrtho2D megszorozza az aktuális projekciómátrixot a specifikált mátrixszal és ez lesz az új projekciómátrix. A perspektív vetítési mátrix specifikációja a
void gluPerspective(double fovy, double aspect, double near , double far);
eljárás segítségével adható meg, amely szimmetrikus látóteret specifikál.
A fovy adja meg a látótér szögét az x-z sík irányában amit szögben és nem radiánban kell megadni (45-60-90 fok körülire szokás állítani), az aspect a vágási téglalap szélességének és magasságának arányát (aspect=ablakszélesség/ablakmagasság), a near és far pedig a vágósíkok távolságát.
Nyugi nem olyan bonyolult ez, mint amilyen bonyolultan most leírtam. Nézzünk egy kis kódot, hátha úgy érthetőbb lesz: van ugye az előző leckében létrehozott egyszer programocskánk. A következő metódussal kell kiegészítenünk a programunkat:
Nos ezek a mátrixos dolgok azok, amik az említett szükséges kevés matematikai tudás egy részét képezik. Róluk részletesen a transzformációkról szóló részben írok (következő lecke, nem lesz nehéz, de nagyon fontos). Csak, hogy tudjátok:
A fenti tutorial PowR által írt a http://free-pascal.extra.hu/ oldalon megtalálható OGL tutorial alapján készült el. Köszönet érte PowR-nek, valamint Kuba Attila - OGL Programozása jegyzetének!
A fovy adja meg a látótér szögét az x-z sík irányában amit szögben és nem radiánban kell megadni (45-60-90 fok körülire szokás állítani), az aspect a vágási téglalap szélességének és magasságának arányát (aspect=ablakszélesség/ablakmagasság), a near és far pedig a vágósíkok távolságát.
Nyugi nem olyan bonyolult ez, mint amilyen bonyolultan most leírtam. Nézzünk egy kis kódot, hátha úgy érthetőbb lesz: van ugye az előző leckében létrehozott egyszer programocskánk. A következő metódussal kell kiegészítenünk a programunkat:
private void Reshape() { if (glControl.Height == 0) { ClientSize = new Size(glControl.Width, 1); } float w = glControl.Width; float h = glControl.Height; Gl.glMatrixMode(Gl.GL_PROJECTION); Gl.glLoadIdentity(); Gl.glViewport(0, 0, (int)w, (int)h); Glu.gluPerspective(45, w / h, 0.1, 1000); Gl.glMatrixMode(Gl.GL_MODELVIEW); Gl.glLoadIdentity(); }A Reshape() metódus segítségével mindig beállítjuk a viewport-ot és az aspect ratio értékét. Ezért majd a Form OnResize metódusába is meghívjuk. Mivel az aspect=w/h ezért ellenőrizni kell, hogy a h ne vegyen fel soha nulla értéket. Ezután már csak a gluPerspective az egyetlen ismeretlen parancs. Először nézzük akkor ezt. Ahogy látszik 45 fok a látószög, a képarány w/h, a közeli vágósík a nézőponttól (szem) 0.1 távolságra van ennél közelebbi dolgok nem látszanak, a távoli vágósík 1000 távolságra van (jó messze). Ezután meg kell hívnunk a Render() metódust a Reshape() után az OnResize metódusban. A Render eljárást egy sorral kell még egészítenünk:
Gl.glTranslatef(0.0f, 0.0f, -5.0f);
Nos ezek a mátrixos dolgok azok, amik az említett szükséges kevés matematikai tudás egy részét képezik. Róluk részletesen a transzformációkról szóló részben írok (következő lecke, nem lesz nehéz, de nagyon fontos). Csak, hogy tudjátok:
- glLoadIdentity - betölti az egységmátrixot (ezt teszi aktívvá)
- glMatrixMode - kijelöli az aktuális mátrixmódot (amin majd operálunk)
- glTranslatef - a megadott irányba eltolja az egész "világot"
A fenti tutorial PowR által írt a http://free-pascal.extra.hu/ oldalon megtalálható OGL tutorial alapján készült el. Köszönet érte PowR-nek, valamint Kuba Attila - OGL Programozása jegyzetének!
Szia!
VálaszTörlésElőször is szeretném megköszönni munkádat, az itteni cikkek rengeteget segítenek. Hogy őszinte legyek, nem a köszönetnyílvánítás miatt írtam elsősorban, hanem azért, mert akadt egy kis gondom a vetítésekkel. Egész pontosan a GL.Translate() függvénnyel. OpenTK-t használok Visual Studio 2010-zel. A lényeg az, hogy ha 1-nél nagyobb számot írok akár az x,y, vagy z koordinátához, nem jelenik meg a színes négyzetem, illetve a 'z' értékének módosításával látszólag semmi nem történik. Nem igazán látom mi a probléma. Linkelek egy forráskódot is: Forrás az itt kikommentelt függvénnyel van problémám.
Segítséged előre is köszönöm.
Üdv: Attila