Pamācības

OpenGL pamācība

OpenGL pamācība

GiGa, 18.01.2010

Lejupielādēt: šeit

Ievads
 
Labdien,
 
tas, ko Tu tagad lasi, ir mans pirmais tutoriālis (neuzdrošinos šo vārdu tulkot), kas, cerams, palīdzēs kādam spēļu radīšanas (no programmēšanas puses) alkstošam cilvēkam (pieņemsim Tev) uzsākt šo grūto dzīves ceļu. Šis ir mans pirmais mēģinājums rakstīt ko tamlīdzīgu, un, cerams, gūstot lasītāju atzinību, uz tā pamata izveidosies vesela tutoriāļu sērija, kas palīdzēs apgūt ar spēļu radīšanu saistītās lietas, sākot no vienkāršas spēles loga izveidošanas un beidzot ar jaunāko un modernāko tehnoloģiju pielietošanu grafikas, skaņas un citu efektu radīšanai.
 
Dažas lietas, ko vajadzētu ņemt vērā, pirms lasīt tālāk. Ar spēļu radīšanu saistītās lietas nav vienkāršas. Apbruņojies ar lielu pacietību un gatavojies daudzām negulētām naktīm, ja gribi kārtīgi izprast šīs lietas un sasniegt ievērības cienīgus rezultātus. Es nesaku, ka tas, ko te varēs izlasīt, ir pareizākais veids, kā programmēt attiecīgās lietas. Es pat nesaku, ka tas būs labs veids, kā programmēt. Es tikai ceru, ka pēc šī materiāla izlasīšanas Tev radīsies kāds priekšstats par to, kā programmēt spēles un attiecīgos elementus, kā arī būs likts labs pamats, lai Tu spētu saprast sarežģītākās lietas un izdomāt efektīvākos to implementēšanas veidus. Ar šo teikumu vajadzētu saprast, ka daudzi pirmie tutoriāļi būs paredzēti galīgiem iesācējiem, bet es ļoti ceru, ka drīz varēsim pāriet pie sarežģītākām lietām. Centīšos terminus no angļu valodas netulkot, tikai tik daudz, kā paskaidrot to būtību, lai nebūtu problēmas sasaistīt te lasīto ar citur atrodamu informāciju angļu valodā. Kā arī, lai izvairītos no stulbiem un nevajadzīgiem latviskojumiem. Kā arī nekautrēšos, pieņemamā līmenī, lietot slengu un izteikties neliterāri, ka tikai doma ir saprotama. Mainīgos un objektus savā kodā saukšu angļu vārdos, atkal, lai būtu vieglāk sasaistīt te lasīto ar angļu valodā esošajiem tutoriāļiem. Cerams, piedosiet ;).
 
Šie tutoriāļi to sākotnējā variantā būs domāti C++ valodai, Dev-C++ IDE un Mingw kompilatoram. Līdz ar to es pieņemšu, ka lasītājam ir vismaz kaut kādas zināšanas par attiecīgo valodu, bet ņemot vērā, ka dažiem no Jums tās varētu būt ne visai lielas, dažos pirmajos tutoriāļos centīšos paskaidrot arī ar valodu saistītās „ne pašsaprotamās” lietas. Lai gan tas viss varētu mainīties daudzu iemeslu dēl – es vienkārši tā nolemšu ;) vai arī kāds cits arī sāks rakstīt mazliet savādākus tutoriāļus un novietot te pat. Nepieņemiet, ka lietas tā turpināsies mūžīgi, bet tāda, kā izskatās, būs to sākotnējā kārtība.
 
Labi, ķersimies pie lietas - Tutoriālis numur 1:
 
Vienkāršs OpenGL logs ar SDL
 
Ja Tev rodas jautājums: ko? Paskaidrošu :) SDL - Simple DirectMedia Layer. Šie skaistie vārdi apzīmē funkciju bibliotēku, kuru es izmantošu savos tutoriāļos loga izveidei, peles un klaviatūras nolasīšanai un tamlīdzīgi. Atzīšos, ar SDL neesmu ilgi pazīstams, tādēļ kļūdu/slikta parauga varbūtība šajā ziņā ir diezgan liela. OpenGL – Open Graphics Library. Šie vārdi, savukārt, apzīmē grafisko funkciju bibliotēku, ar kuras palīdzību mēs zīmēsim uz ekrāna savus trīsstūrīšus un kvadrātiņus visās skaistajās krāsās :) . Ar OpenGL, savukārt, esmu pazīstams diezgan ilgi, lai varētu garantēt +/- pareizu un efektīvu informāciju, bet atkal atgādinu – izmanto manus tutoriāļus kā izziņas līdzekli, nevis kā pareizas un efektīvas programmēšanas paraugus. Atrodi informāciju arī citur, salīdzini un izdari secinājumus par to, kas būtu labāks Tavā konkrētā gadījumā. Pašam domāt ar savu galvu – īpašība, bez kuras programmētājam neiztikt ;) .
 
Un nu pie lietas. Tātad, ko mēs darīsim pirmajā tutoriālī? Ar SDL uztaisīsim spēlei logu, ar iespējām zīmēt tajā izmantojot OpenGL. Un uzzīmēsim tajā rotējošu (ar bultiņām grozāmu) trīsstūri, kurš pietam griezīsies ar vienādu ātrumu neatkarīgi no fps (kadriem sekundē), tādā veidā iepazīstoties ar time based movement. Kāds no tā labums? Esi kādreiz spēlējis spēli, kura uz lēnākiem kompjiem iet ļoti lēni, bet uz ātrākiem pretinieki atnāk no līmeņa otra gala un Tevi nogalina sekundes desmitdaļas laikā? Lūk, piemērs, kādēļ spēles update funkcijā jāņem vērā fps nevis vienmēr jāprogresē pasaule par konstantu laika daudzumu. Un vēl mūsu tutoriālis iekļaus to, ka, nospiežot Escape pogu, programma beigs darbu.
 
Dabūt darbam nepieciešamās lietas par brīvu un legāli vari te. Dev-C++ - http://www.bloodshed.net/dev/devcpp.html . Meklē jaunāko versiju un izvēlies download’u „Dev-C++ 5.0 beta 9 (4.9.9.1) (7.6 MB) with Mingw/GCC 3.3.1 Dev-C++ version 4.9.9.1, includes full Mingw compiler system (GCC 3.3.1) and GDB 5.2.1 See NEWS.txt for changes in this release.” Protams, aizvietojot ciparus ar jaunākajai versijai piederošajiem. SDL var dabūt te - http://www.libsdl.org/download-1.2.php . Meklē SDL-devel-1.2.8-mingw32.tar.gz (Mingw32). Tiešos linkus nedodu, jo tie var laika gaitā mainīties. Uzinstalējam Dev-C++, atarhivējam SDL un pārkopējam SDL direktoriju, kas atrodas ...\SDL-1.2.8\include\ direktorijā uz ...\Dev-Cpp\include\ direktoriju. Un visus failus, kas atrodas ...\SDL-1.2.8\lib\ direktorijā uz ...\Dev-Cpp\lib direktoriju. Vēl, iespējams vajadzēs pārkopēt SDL.dll no ...\SDL-1.2.8\bin\ uz to direktoriju, kur tiks novietots programmmas .exe fails, vai arī uz sistēmas direktoriju. Piemēram - C:\WINNT\system32. Nu mēs esam gatavi sākt darbu.
 
Palaižam Dev-C++ (Ja ļoti gribās, pat varam uzlikt latviešu valodu interfeisam! Bet man šī iespēja, nezin kāpēc, nelikās noderīga, lai arī doma ir jauka un sirdi sildoša :) .) un izvēlamies File->New->Project->Console Application. Noseivojam visus failus un dzēšam ārā visu sourci, kas mums jau dota. Tālāk mums vajag iekļaut vajadzīgās ne-defaultīgās bibliotēkas mūsu projektā. Spiežam Project->Project Options->Parameters un pie „linker” ierakstam šo: „-lmingw32 -lSDLmain -lSDL -lopengl32 -lglu32”. Nu tad ķeramies arī pie pašas sources.
 
#include       //standarta biblioteeka texta ievadei/izvadei
#include     //SDL biblioteekas headers
#include       //OpenGL biblene
#include     //OpenGL utiliitu biblene
//shie chetri vienkaarshi ir vajadziigi, lai piekljuutu mums nepiecieshamajaam funkcijaam
Pievienojam vajadzīgo bibliotēku headerus.
bool Quit=false; //shis mainiihais apziimees, kad mums vajad beigt programmas darbu

bool Keys[256]; //sheit mees glabaasim visu pogu nospieshanas staavokli
//false=nenospiesta; true=nospiesta

float Rotation=0.0f; //lenkjis, par kuru ir paroteejis muusu triistuuris
void RenderScene();//muusu render funkcijas deklareeshana
Komentāri laikam nav vajadzīgi.
int main(int argc, char *argv[]) //funkcija, ar kuru muusu programma saaks darbu
{
    printf("Meeginu inicializeet SDL...\n"); //shie texti netiek izvadiiti uz ekraana
                                            // bet gan tiek saglabaati "log" failaa - stdout.txt
                                            //direktorijaa, kur atrodas muusu .exe
    if((SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER)==-1))//ja nav izdevies inicializeet video un taimeri
        {
        printf("Ehh, nesanaaca: %s.\n", SDL_GetError());//uzrakstam, ka neizdevaas un kaapeec
        return -1;//izejam no programmas
        }
    printf("SDL inicializeets.\n");//ir ok  
No sākuma mēģinām inicializēt SDL ar video modes un taimera atbalstu. Tas tiek norādīts sa’OR’ojot kopā konstantes SDL_INIT_VIDEO un SDL_INIT_TIMER. Tiem, kas nezin – tas nozīmē, ka rezultējošajam mainīgajam divi biti, kuri apzīmē video un taimeri būs 1. Pārējie 0. Ja nu tas neizdodas, tad failā ierakstam kāpēc - SDL_GetError() atgriež char* tipa mainīgo – pointeri uz NULL terminētu stringu ar pēdējā errora aprakstu.
    int Width = 800; //muusu ekraana platums
    int Height = 600; //muusu ekraana augstums
    int Bpp = 32;    //muusu ekraana biti uz pixeli
    int Flags = SDL_OPENGL | SDL_FULLSCREEN;
        //mees gribam muusu logu fullscreen un ar OpenGL atbalstu
    SDL_Event Event; //ar shii objekta paliidziibu ar mums sazinaasies SDL 
Šos mainīgos lietosim taisot mūsu logu. Flags – kopā sa’OR’oti mainīgie, kas apzīmē mums vajadzīgās loga modes. Šinī gadījumā OpenGL atbalstu un „logs pa visu ekrānu”. Event ir struktūra, ar kuras palīdzību SDL mums paziņos dažādus eventus, pieņemsim pogas spiedienu, ekrāna pārbīdi (ko mums pašiem gan nevajag apstrādāt) un citas.
    if( SDL_SetVideoMode( Width, Height, Bpp, Flags ) == 0 ) //ja nu neizdodas uztaisiit logu
        {
        printf("Nevar iesleegt video modi: %s\n", //pasaka ka neizdevaas
             SDL_GetError( ) );                   //un kaapeec
        SDL_Quit();                               //izsleedzam SDL
        return -1;                                //izejam no programmas
        } 
Mēģinam uztaisīt logu ar izvēlētajiem settingiem. Ja neizdodas, uzrakstam kāpēc. Un neaizmirstam izslēgt SDL, jo nu tas jau ir iedarbināts – ar SDL_Init().
    glViewport(0,0,Width,Height);                //uzsetojam ogl viewportu
    glShadeModel(GL_SMOOTH);                     //"gludais sheidings" :)
   glClearColor(0.0f, 0.0f, 0.0f, 0.0f);        //ekraana notiiriishanas kraasa 
glViewPort – apzīmē, kuru loga daļu mēs atvēlam OpenGL. Sākot no punkta 0,0 – atskaite pret loga apakšējo kreiso stūri. Width pikseļus pa x asi un Height pikseļus pa y asi. Citiem vārdiem – visu logu. ShadeModel apzīmē, kā tiks interpolētas vertexu vērtības pa mūsu trīsstūri. FLAT šeidings nozīmētu, ka, piemēram, krāsa uz visu trīsstūri būtu tāda pati, kā pirmajam vertexam. SMOOTH šeidings nozīmē, ka krāsa lēnām un gludi pāries no viena vertexa uz citu. ClearColor nozīmē to, uz kādu krāsu mēs tīrīsim ekrānu katra kadra sākumā.
while(!Quit)//kameer nav jaaiziet no programmas, galvenais programmas cikls
       {
       while(SDL_PollEvent(&Event))//kameer sdl mums suuta kaadu zinju
              {
              switch(Event.type)//kaada veida zinja?
                    {
                    case SDL_KEYDOWN://nospiesta poga
                        Keys[Event.key.keysym.sym]=true;//atziimeejam attieciigaas pogas nospieshanu
                        break;
                    case SDL_KEYUP://atlaista poga
                        Keys[Event.key.keysym.sym]=false;//atziimeejam attieciigaas pogas atlaishanu
                        break;
                    case SDL_QUIT://nospiesta loga aizveershanas poga
                        Quit = true;//atziiimeejam, ka jaaiziet no progas
                        break;
                    }
               } 

Te laikam komentārus arī nevajag.
       //kad SDL mums vairs nesuuta zinjas, turpinam programmas darbu
        if(Keys[27])//ja nu nospiests ESC?
                {
                Keys[27]=false;
                Quit=true;//atziiimeejam, ka jaaiziet no progas
                }   
        RenderScene();//ziimeejam triistuuri
        SDL_GL_SwapBuffers();//nosvapojam buferus 
Mūsu programmas galvenais cikls. Ja ir nospiests ESC ( 27 ir Escape pogas kods) izejam no programmas. Tālāk izsaucam mūsu renderēšanas (skaistāks apzīmējums zīmēšanai ;) ) funkciju. Un visbeidzot to ekrāna buferi, kurā pašlaik zīmējām uzliekam kā redzamo, bet to, kurš tikko bija redzams paņemam kā to, uz kura tagad zīmēsim.
     printf("Izsleedzam SDL...\n");//bye bye
    SDL_Quit();//izsleedzam sdl
    printf("Izejam no programmas...\n");//viss ok
    return 0;//izejam no progas<
} 
Nu un tas arī viss :) atliek tikai tuvāk apskatīt mūsu renderēšanas funkciju.
void RenderScene()
{
    static unsigned Last=SDL_GetTicks();//sheit mees glabaajam peedeejaa kadra laiku
    //atceries, ka shis te inicializaacijas SDL_GetTicks() tiks izsaukts tikai pirmajaa
    //funkcijas reizee
    glClear(GL_COLOR_BUFFER_BIT);//notiiram ekraanu uz melnu kraasu
    glMatrixMode(GL_PROJECTION);//iesleedzam projekcijas matricu, kaa tekosho
    glLoadIdentity();//resetojam to matricu uz identitaates matricu - taadu, kas nedara neko
    glOrtho(-400.0f,400.0f,-300.0f,300.0f,0.0f,1.0f);//paartaisam projekcijas matricu taa,
                                                //lai taa ietvertu apgabalu (-400;400)(-300;300)
    glMatrixMode(GL_MODELVIEW);//iesleedzam modelview matricu, kaa tekosho
    glLoadIdentity();//resetojam to matricu uz identitaates matricu - taadu, kas nedara neko
    glRotatef(Rotation,0.0f,0.0f,1.0f);//izmainam modelview matricu taa, lai vertexi, ar to
                            //pareizinati, pagrieztos par Rotation graadiem ap z asi
Last – statiskais mainīgais (vērtība nezūd izejot no funkcijas), kurš saglabās laiku, kad tika renderēts pēdējais kadrs. SDL_GetTicks() atgriež milisekundžu skaitu, cik ir pagājušas no SDL inicializācijas. Tālāk mēs notīrām ekrānu uz kādu krāsu (atceries glClearColor ? ). Tad uzsetojam projekcijas matricu. Un arī modelview matricu. Pagaidām neuztraucies, ja nesaproti, tas būs nākošā tutoriāļa temats. Tas, kas te notiek, vienkāršā valodā nozīmē, ka mūsu ekrāns aptvers „telpas” apgabalu no -400 līdz 400 pa x asi, un no -300 līdz 300 pa y asi. Tad mēs vēl pagriežam mūsu trīsstūri par Rotation grādiem ap z asi jeb ap 0,0 punktu xy plaknē.
    glBegin(GL_TRIANGLES);//saakam ziimeet triistuurus
    glColor3f(1.0f,0.0f,0.0f);//noraadam kraasu
    glVertex2f(-150.0f,-130.0f);//noraadam vertexa poziiciju
    glColor3f(0.0f,1.0f,0.0f);
    glVertex2f(150.0f,-130.0f);
    glColor3f(0.0f,0.0f,1.0f);
    glVertex2f(0.0f,130.0f);
    glEnd();//beidzam ziimeet triistuururs 
Šeit mēs zīmējam mūsu trīsstūri. Ar glBegin(GL_TRIANGLES); mēs pasakām, ka tūlīt zīmēsim trīsstūri/us. Ar glColor3f(1.0f,0.0f,0.0f); norādām nākamā vertexa krāsu. Ar glVertex2f(-150.0f,-130.0f); norādām 2 vertexa koordinātes – x un y. Kad savācas trīs punkti tiek uzzīmēts trīsstūris. Ja mēs turpinātu norādīt punktus (vertexus), tad pēc katriem trīs tiktu zīmēts trīsstūris. Ar glEnd() beidzam trīsstūru zīmēšanu.
    unsigned Now=SDL_GetTicks();//dabuujam tekosho laiku
    unsigned Diff=Now-Last;//dabuujam starpiidu
    float Advance=Diff/1000.0f;//starpiibu no milisekundeem paarveersham sekundees
    Last=Now;//pierakstam peedeejaa kadra laiku
Nolasām konkrētā mirkļa laiku (milisekundes no SDL inicializācijas) un atņemam pagājušā kadra laiku. Iegūstam starpību milisekundēs (1000 uz vienu sekundi), tāpēc izdalām ar 1000, lai varētu rotācijas ātrumu norādīt grādos sekundē. Beigās- pēdējā kadra laiks = šī kadra laiks.
        if(Keys[SDLK_LEFT])//ja nospiesta kreisaa poga
        {
        Rotation+=170.0f*Advance;//roteejam pa kreisi ar 170deg/sec
        }
    if(Keys[SDLK_RIGHT])//ja nospiesta labaa poga
        {
        Rotation-=170.0f*Advance;//roteejam pa labi ar 170deg/sec
        } 
} 


Ja nospiesta bultiņa pa kreisi, rotējam pa kreisi ar ātrumu 170 grādi sekundē. Ja labā poga, rotējam pa labi ar ātrumu 170 grādi sekundē. Viss. Pirmā tutoriāļa beigas. Nākamajā centīšos pastāstīt, kā izmantot modelview un projekcijas matricas, lai apskatītu objektus sev vēlamajā rakursā. Kā iedarbināt perspektīvu (lai redzētu kaut ko 3dimensionāli ;) ). Nu labi, šovakar mani alus krājumi ir izsīkuši un Tev nav vairs ko teikt. Tas nozīmē, ka jādodas vien gulēt. Bet Tu gan pārliecinies, ka visu iepriekš minēto labi saprati un, ja kas tomēr ir neskaidrs, prasi forumos: dev.gamez.lv . Vai arī sūti atsauksmes uz giga86@tvnet.lv .

 

Viss, veiksmi un uz redzēšanos nākamreiz.

Komentārus var izteikt šeit!
Izejas kods!

 

Papildus materiāli angļu valodā:

Ievads C++ http://www.cplusplus.com/doc/tutorial/
OpenGL mājaslapa http://www.opengl.org/
SDL mājaslapa http://www.libsdl.org/index.php
GameDev tutoriāļi http://nehe.gamedev.net/
Citi GameDev tutoriāļi http://www.gametutorials.com/

Līdzīgi raksti:

Autorizācija

Lietotājs

Parole


Reģistrēties Aizmirsu paroli