Ez a cikk segítségedre lehet abban, hogy pár egérkattintásból,
és pár sorból megvalósítsd első forgó kockádat.
Üdv mindenkinek!
Az alábbi címről le is ránthatjuk: devcpp
Na most gonoszan lerövidítem magam! Elkezdhetném irkálni, hogy a Windows így meg úgy meg a WINAPI-val így kell, meg úgy kell, de azt hiszem, most csalni fogok.
Legyünk rövidek és legyünk lusták! Ha még nem tetted meg, akkor nézd meg szépen, hogy mi bújik meg a Fájl/Új/Projekt menü alatt!
Egyszerű a tárház. Van itt minden. Windows Application vagy Console Application a kismókusoknak, vagy Static Library vagy DLL a nagymókusoknak. De ha jobban szemügyre vesszük, akkor mit találunk még?
Létrehozunk egy Windows ablakot, inicializálunk OpenGL környezetet, és rajzolunk addig, míg ESC-et nem nyomunk. Majd megszüntetjük az OpenGL környezetet.
Egyszerűen tömören: (Nagy levegő)
A struktúra által kreálunk egy ablakot (CreateWindow függvény).
Az így kapott ablak leíróhoz (hWnd) illesztünk OpenGL környezetet (EnableOpenGL függvény).
Az (EnableOpenGL függvény) feladata, hogy megfeleltessen egy pixelformátum leírót az ablakhoz (PIXELFORMATDESCRIPTOR). Ebben a struktúrában megadhatjuk az OpenGL beállításokat: színmélység, (zbuffer) mélységi buffer, lapozási technika, szín rendszer használata.
Miután az (EnableOpenGL függvény) megfutott, kezdődhet a fő rajzolási ciklus, mely alapesetben üzenet feldolgozást végzi, de ha éppen nincs semmi dolga, akkor rajzol egy forgó háromszöget.
Az üzenetek feldolgozásáért egy speciális üzenet feldolgozó függvény a felelős, amit (WndProc függvényként) definiál a példa. Ebben a függvényben határozhatjuk meg, hogy bizonyos esemény bekövetkezése esetén mit csináljon a program. E pillanatban a WM_CLOSE és WM_KEYDOWN események vannak kifejtve rendre magyarul… Az alkalmazás bezárása esemény küldjön a ciklusból kilépés üzenetet, plusz az ESC billentyű lenyomásakor is küldjünk egy kilépés üzenet.
Ezt a dolgot hívják úgy, hogy esemény vezérelt program. Üdvözöllek a Windows lelkivilágában. :)
(Szusz kifúj…)
Hát ez ilyen. De hát hol van a kockánk?
Töröljük ki ezeket az utasításokat:
glBegin (GL_TRIANGLES);
glColor3f (1.0f, 0.0f, 0.0f); glVertex2f (0.0f, 1.0f);
glColor3f (0.0f, 1.0f, 0.0f); glVertex2f (0.87f, -0.5f);
glColor3f (0.0f, 0.0f, 1.0f); glVertex2f (-0.87f, -0.5f);
glEnd ();
Miután kitöröltük és fordítunk, futtatjuk a nagy büdös semmit, látjuk.
Mi történik?
(glClearColor) beállítja a törlési színt (lehet játszadozni az első három paraméter R, G, B színkomponensek), a színek 0 és 1 között adhatóak meg. Példaként a narancssárga előállítás (mspaint) segítségével.
glClear függvény meghatározza, hogy melyik buffert töröljük, jelen esetben csak a szinbuffert kell törölni. glPushMatrix / glPopMatirx páros lényeges utasítások. Ezzel a két paranccsal helyezünk verembe mátrixokat, jelen esetben feladatuk, hogy az épp aktuális transzformációs mátrixot elmentjük (verem tetejére rakjuk, PUSH) majd onnan levesszük, POP. E két parancspáros közé helyezzük most a rajzolást és a hozzá tartozó transzformációt. Ez a transzformáció most a forgatás és az eltolás lesz.
glRotatef (theta, 0.0f, 0.0f, 1.0f);
glRotatef (theta, 0.0f, 1.0f, 0.0f);
glRotatef (theta, 1.0f, 0.0f, 0.0f);
A függvény paraméterei a következők: 1 paraméter: az elforgatás szöge, a 2, 3, 4 pedig az elforgatás vektora. Most egyet forgatunk rajta a z tengelyen, majd egyet y tengelyen, majd egyet x-en is. Miután képernyőt töröltünk, buffert ürítettünk, transzformációs mátrixot mentettünk, majd forgattunk, észrevesszük, hogy nincs semmi DOLOG „The Thing” amin végrehajtanánk ezeket. Nosza illesszük be az alábbi kódot az utolsó glRotate függvény és glPopMatrix közé!
glColor3f( 1.0f, 0.0f, 0.0f );
glBegin(GL_QUADS);
glVertex3f( -1.0f, -1.0f, 1.0f );
glVertex3f( 1.0f, -1.0f, 1.0f );
glVertex3f( 1.0f, -1.0f, -1.0f );
glVertex3f( -1.0f, -1.0f, -1.0f );
glEnd();
glColor3f( 0.0f, 1.0f, 0.0f );
glBegin(GL_QUADS);
glVertex3f( -1.0f, 1.0f, 1.0f );
glVertex3f( 1.0f, 1.0f, 1.0f );
glVertex3f( 1.0f, 1.0f, -1.0f );
glVertex3f( -1.0f, 1.0f, -1.0f );
glEnd();
glColor3f( 0.0f, 0.0f, 1.0f );
glBegin(GL_QUADS);
glVertex3f( -1.0f, 1.0f, 1.0f );
glVertex3f( 1.0f, 1.0f, 1.0f );
glVertex3f( 1.0f, -1.0f, 1.0f );
glVertex3f( -1.0f, -1.0f, 1.0f );
glEnd();
glColor3f( 1.0f, 0.0f, 1.0f );
glBegin(GL_QUADS);
glVertex3f( -1.0f, 1.0f, -1.0f );
glVertex3f( 1.0f, 1.0f, -1.0f );
glVertex3f( 1.0f, -1.0f, -1.0f );
glVertex3f( -1.0f, -1.0f, -1.0f );
glEnd();
glColor3f( 1.0f, 1.0f, 1.0f );
glBegin(GL_QUADS);
glVertex3f( -1.0f, -1.0f, 1.0f );
glVertex3f( -1.0f, 1.0f, 1.0f );
glVertex3f( -1.0f, 1.0f, -1.0f );
glVertex3f( -1.0f, -1.0f, -1.0f );
glEnd();
glColor3f( 0.0f, 1.0f, 1.0f );
glBegin(GL_QUADS);
glVertex3f( 1.0f, -1.0f, 1.0f );
glVertex3f( 1.0f, 1.0f, 1.0f );
glVertex3f( 1.0f, 1.0f, -1.0f );
glVertex3f( 1.0f, -1.0f, -1.0f );
glEnd();
Mentsünk, majd fordítsunk CTRL+S, majd F9.
Mielőtt még feladnánk OpenGL-es jövőnket, és elmennénk Kubába gyöngyhalásznak, nézzük meg, mi történik, és formáljunk kockát. (De azért jól néz ki ez az effekt.)
A glVertex3f paranccsal határozunk meg egy pontot a térben. Miről mesél nekünk ez a parancs? Először is a parancs eleje (gl) mesél nekünk arról, hogy ez egy OpenGL specifikus parancs. A közepe a (vertex) szó mondja, hogy itten most egy 3D pont pozíciójáról van szó, ez lehet akár (color) is, ami színt határoz meg vagy (normal), ami majd az árnyaláshoz fog kelleni, meg még sok más egyéb. (Majd később találkozunk még ezekkel.) A végén jelzi a parancs, hogy (3f). Mit is jelent?
Hát igen a függvény 3 paramétert vár melyeknek típusa (float), tehát az alábbi parancs glVertex3f( 1.0f, 1.0f, 1.0f, ); egy pontot határoz meg a koordináta rendszerben, melynek koordinátái (x, y, z) 1, 1, 1.
Nézzük a primitívek meghatározását.
Egy ilyen glBegin és glEnd páros között egy primitívet határozunk meg. Ez elég sokféle lehet.
Ha a glBegin/glEnd páros utasításokat használjuk, akkor glBegin párméterében az alábbi paramétereket állíthatjuk:
GL_POINTS:
egy pontot határoz meg a térben, elég hozzá egy (vertex) pozíció.
GL_LINES:
egy szakaszt határoz meg a térben, 2 (vertex) pozíció szükséges hozzá.
GL_TRIANGLES:
egy háromszöget határoz meg a térben, 3 (vertex) pozíció szükséges hozzá.
GL_QUADS:
egy négyszöget határoz meg a térben, 4 (vertex) pozíció szükséges hozzá.
GL_POLYGON:
egy sokszöget határoz meg a térben, és annyi (vertex) pozíciót határozol meg hozzá, amennyit csak akarsz. ;)
És ezen kívül még van egy jó pár, nézd meg itt!
Tehát akkor látjuk is, hogy egyenként határozunk meg négyszögeket, rendre belőle hat darabot, mivel a kockának hat oldala van. De miért nem kocka a kocka?
A válasz a perspektív leképezésben van. Ebben a programban nincsen beállítva a perspektív leképezés, sőt a zbuffer algoritmus sem működik. (Ezt abból is láthatjuk, hogy glClear paraméterben csak szín buffert ürítünk). Írjuk az EnableOpenGL függvényhívás után az alábbi kódot:
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
gluPerspective( 66.67, 1.0, 1.0, 100.0 );
gluPerspective függvény határozza meg a látószöget, a képszélleség és képmagasság torzítási arányát (width/height) és a nézeti gúla elülső és hátsó vágó síkjának a távolságát. Boldogan fordítanánk de sajnos „gluPerspective’ undeclared (first use this function)” fordító hiba üzenetet kapjuk.
Hát igen a gluPerspective a (GLU) könyvtár része, amely egy hasznos kiegészítés az OpenGL-hez (nézeti beállítások, kamerakezelés, 3D primitívek). Természetesen ami (GLU)-ban megtalálható, azt mátrix és vektor műveletek segítségével meg lehet valósítani. (Majd lesz olyan, hogy mutatok erre példát).
De most inkább legyünk lusták, és használjuk a (GLU) könyvtárat. Adjuk hozzá a (GLU) include-ot a forrásunkhoz.
#include <gl/glu.h>
Na most meg mi a baj?
„undefined reference to `gluPerspective@32’”
Hát adjuk hozzá a statikusan linkelt könyvtárat!
Projekt/Projekt Beállítások/Paraméter fül
Na akkor fordítsunk, futassunk. F9
Addig OK, hogy forgatjuk azt a kockát, de hiszen benne vagyunk a kocka közepében. (Ami mondjuk tök jó, ha SkyBox-ot csinálunk, de azt majd később.) ;)
Tehát jöjjünk ki belőle, mondjuk úgy 3 egységnyit!
glPushMatrix ();
glTranslatef( 0.0f ,0.0f, -3.0f);
glRotatef (theta, 0.0f, 0.0f, 1.0f);
glRotatef (theta, 0.0f, 1.0f, 0.0f);
glRotatef (theta, 1.0f, 0.0f, 0.0f);
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
gluPerspective( 66.67, 1.0, 1.0, 100.0 );
glEnable( GL_DEPTH_TEST );
glClear ( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
És monámú! :) Pörög, forog.
Optimalizáljunk!
Mint már említettem, az OpenGL parancsok végén jelezzük, hogy milyen típusú paramétert adunk át neki.
Hát látjuk hogy (float)-ot használunk, de nem használjuk a tizedes jegyeket. Akkor nyugodtan írhatunk (short)-ot mert az ugye kisebb helyen is elfér. :) glVertex3s( -1, -1, 1 );
Használjunk glColor3ub formát, amiben még jobban meg tudjuk adni az mspaintban adott vörös zöld kék kódokat. Piros szín: glColor3ub (255, 0, 0);
Ez a két pont csak ábrázolás mód, mert az OpenGL legbelül úgy is floatként ábrázolja az értékeket, ezért inkább arra kéne odafigyelni, hogy próbáljuk minimalizálni a glBegin/glEnd hívásokat. Miután felsoroltuk a 4 (vertex) pozíciót a QUAD-hoz, akkor nem kell lezárni a primitívet, hanem írhatjuk tovább, hiszen okos, és az új 4-es (vertex) pozíciókat megint csak négyszögé alakítja.
Tehát a rajzoló kódot imígyen is lehet helyettesíteni:
glBegin(GL_QUADS);
glColor3ub( 255, 0, 0 );
glVertex3s( -1, -1, 1 );
glVertex3s( 1, -1, 1 );
glVertex3s( 1, -1, -1 );
glVertex3s( -1, -1, -1 );
glColor3ub( 0, 255, 0 );
glVertex3s( -1, 1, 1 );
glVertex3s( 1, 1, 1 );
glVertex3s( 1, 1, -1 );
glVertex3s( -1, 1, -1 );
glColor3ub( 0, 0,255 );
glVertex3s( -1, 1, 1 );
glVertex3s( 1, 1, 1 );
glVertex3s( 1, -1, 1 );
glVertex3s( -1, -1, 1 );
glColor3ub(255, 0, 255 );
glVertex3s( -1, 1, -1 );
glVertex3s( 1, 1, -1 );
glVertex3s( 1, -1, -1 );
glVertex3s( -1, -1, -1 );
glColor3ub(255,255,255 );
glVertex3s( -1, -1, 1 );
glVertex3s( -1, 1, 1 );
glVertex3s( -1, 1, -1 );
glVertex3s( -1, -1, -1 );
glColor3ub(0, 255, 255 );
glVertex3s( 1, -1, 1 );
glVertex3s( 1, 1, 1 );
glVertex3s( 1, 1, -1 );
glVertex3s( 1, -1, -1 );
glEnd();
Na hát mára ennyit. A lecke forráskódja megtalálható itt, de inkább ajánlanám, hogy írjuk meg szépen kézzel, és ebben ne legyünk lusták! ;)
Segítő Orsi, az én hősöm. :)
[ edited Mar.24. 01:40 ]
Segítő Orsi mindenki barátja :)
Az olyan, mint a Word-ben a segítőkész irattűző?
Két megjegyzés a cikkel kapcsolatban:
1. A Visual C++ is ingyen van (Visual C++ 2005 Express), és abban legalább van épkézláb debugger.
2. A glVertex3f (meg a glBegin..glEnd úgy általában) minden jó érzésű 3D-programozó ősellensége kell, hogy legyen. Ugyanezt vertex array-jel megoldva nem lett volna hosszabb a kód, viszont egyrész gyorsabb, másrészt sokkal kulturáltabb lett volna. A glBegin..glEnd nem mesh-ek kirajzolására lett kitalálva.
Teljesen igazad van Jimmi mind két pontban.
De a cikk egy gyors 10 perces megoldást akar nyújtani. Ezért próbáltam nem túl bonyolítani ( glBegin/glEnd vs. vertex array ).
Egyszerű könnyen összedobhatóvá akartam csinálni a leckét:
Visual C++ 2005 Express telepítése nem egyszerű és gyors ha nincs a gépeden .NET és WinSDK ellenben DevC++ szolgáltat minimál WinSDK-t és egy nagyából jól használható IDE-t és pár next alatt felmegy. Nagy tudomány nem kell neki.
A cél közönség a kezdő demoscenerek akiknek örömet jelent egy szimpla kocka forgatása is. Természetesen tervbe van mindenféle jó ötlet, jó tanács, demos fogások cikké formálása is de most ez kezdésnek szerintem bőven elég.
Egyébként működhetne úgy a dolog, hogy ha hiányosságot veszünk észre másvalaki cikkében, azt hamar fogjuk és megírjuk cikkben. Ezzel is gyarapodunk és okosodunk;)
Jó kis tut! Köszi aha!
Lesz folytatása? Pl. hogyan írhatom ki a képen látható Hello world opengl szöveget
Arról sose találok tutorialt, hogyan tudok pixeleket kirakni a képernyőre opengl-el.
elöre is köszönöm ha tudna valaki segíteni
Végre egy coder cikk! Te vagy a legjobb, Aha!
(bár még nem olvastam el (de el fogom!), meg OpenGL nem is igazán izgat, de ettől még királyság! :))
Folytasd!
az a szivas, hogy nehe ota mindenki kb ugy van vele, mint Te, Bery… Lelkesedik, hogy dekurvajo, de alapvetoen nem erdekli…
Na, fasza! Konkurrencia! :)) En is viszek mar egy ideje egy OpenGL cikksorozatot, meg newbie-supportot nyujtok forumokon. Foleg mert imadom az OpenGL-t, masreszt, mert kicsit elegem van a DX-majmolasbol, mikozben az OpenGL egy kivalo API. :P
Mint totál kezdő arcnak ez most nagyon jól jött ,remélem lesz folytatás:)
tty…
Visual C++ 2005 Express telepítése nem egyszerű
ezzel vitatkoznek, annyira nehez mint felrakni egy total commandert kb…
Sziasztok! Én inkább D3D-ben szeretek programozni, arról is lesz majd cikk?
Ha gondolod akkor felhuzzuk a todo-ra, bar szerintem a DirectX SDK-nal jobb tutorialokat keresve se talalsz :)