Warsztat.GDCompo!ProjektyMediaArtykułyQ&AForumOferty pracyPobieranie

Opisz napotkaną sytuację, a redakcja niezwłocznie znajdzie rozwiązanie!

wyślij anuluj

Open GL - Pierwszy program

Uwaga! Tekst posiada 1 niepotwierdzonych zmian!

Tekst został importowany z Warsztatowych artykułów. Jego oryginalnym autorem jest Wojciech Dudek. Jeżeli został importowany poprawnie, usuń ten szablon!

Autor: Wojciech Dudek

Wstęp, czyli po co komu ten artykuł Opisy Open GL można znaleźć w wielu miejscach (książki, pliki z sieci itp.). W większości jednak są one albo bardzo nieprecyzyjne, albo bardzo szerokie, co skutecznie do nich zniechęca osoby chcące zacząć zabawę z grafiką 3D. W tym artykule chcę przedstawić podstawowy program w standardzie GL, od jakiego powinno się zaczynać. Konkretnie, bez zbytniego wgłębiania się opiszę, jak zbudować pierwszą aplikację korzystającą z Open GL. Uwierzcie mi 90% rozbudowanych programów w GL opiera się na niej. W opisie tym nie ma podanych nagłówków funkcji wraz z opisem, zakładam, że każdy coś na ten temat ma. Są za to dość dokładnie opisane kolejne kroki przykładowego programu. Mam nadzieję, że artykuł będzie pomocą w rozpoczęciu programowania w Open GL.

1. Co jest potrzebne do pisania programów w Open GL

  • Kompilator języka C/C++ generujący kod 32 bitowy, czyli po ludzku taki, na którym można tworzyć programy pod Win 95 (lub nowszym),
  • Biblioteki statyczne Open GL: opengl32.lib i glu32.lib,
  • Pliki nagłówkowe Open GL: gl.h i glu.h,
  • W systemie MUSI znajdować się sterownik Open GL o nazwie opengl32.dll i biblioteka pomocnicza glu32.dll. Mogą być w katalogu programu, albo w podkatalogu Windows'a /System,
  • Bardzo zalecany byłby akcelerator 3D, chociaż nie jest konieczny.
    Wszystko to (oprócz bibliotek .dll) jest w pliku do tego artykułu gl.rar. [Niestety plik zaginął - przyp. redakcja]

Uwaga 1: Biblioteki statyczne (lib) są różne dla Borland C++ i Visual C++. Są w podkatalogach: /libBOR i /libVC.
Uwaga 2: Sterownik opengl32.dll dla niektórych kart może mieć inną nazwę. No cóż, trzeba poeksperymentować (np. skopiować go do katalogu programu i zmienić nazwę).

2. Szkielet programu w Open GL

Głównym plikiem programu jest gl.cpp.
Jest to standardowy program pod Win 95, w API.
Jest funkcja WinMain:

int WINAPI WinMain(HINSTANCE Zad,HINSTANCE, LPSTR,int To)

która inicjuje okno i rozpoczyna cykl obsługi komunikatów.

W programie Open GL we właściwościach okna należy wpisać: WS_CLIPCHILDREN i WS_CLIPSIBLINGS, zalecam też WS_POPUP, czyli pracę na pełnym ekranie.

Dalej znajduje się funkcja która obsługuje komunikaty:

LRESULT CALLBACK ProcOkna(HWND Okno,UINT Kom,WPARAM WP,LPARAM LP)

Interesują nas zdarzenia: . Rozpoczęcie programu: WM_CREATE, . Naciśnięcie klawisza: WM_KEYDOWN, . Zmiany rozmiaru okna: WM_SIZE, . Zakończenia programu: WM_DESTROY, . Odrysowywania zawartości okna: WM_PAINT.

Program Open GL podczas rozpoczęcia programu inicjuje pewne rzeczy (o tym dalej). Odrysowanie zawartości okna to najlepsza część programu (GL rendering). Musimy wychwycić naciśnięcie klawiszy: kursorów, Entera i Esc. Na końcu programu pewne rzeczy należy doprowadzić do stanu przed jego uruchomieniem. Zmiana rozmiaru okna nam raczej nie grozi-rysujemy po całym ekranie. Z pewnych jednak względów ten komunikat będzie jednak potrzebny.

3. Inicjalizacja Open GL

Jest realizowana w ramach komunikatu WM_CREATE, i jest to najdłuższa (i niezbędna) część programu.

Po kolei działa to tak:

hDC=GetDC(Okno); //Pobranie tzw. kontekstu okna SetDCPixelFormat(hDC); //Ustawienie formatu pixeli (o tym poniżej) hRC=wglCreateContext(hDC); //Stworzenie tzw. kontekstu Open GL wglMakeCurrent(hDC, hRC); //I ustawienie go glViewport(0,0,GetSystemMetrics( SM_CXSCREEN ),GetSystemMetrics( SM_CYSCREEN )); // Ustawienie widoku, czyli tej części ekranu, na której będziemy renderować. // W tym przypadku cały ekran gluPerspective(90.0f,1.0f,1.0f,1000.0f); //Ustawienie tzw. ostrosłupa widzenia. // Kamera będzie mieć pole widzenia 90 stopni, będzie widzieć obiekty //położone względem niej od 1 pixla do 1000 pixli, // i będzie widzieć obiekty nie zniekształcone glEnable(GL_DEPTH_TEST); //Włączenie usuwania powierzchni zasłoniętych glDepthFunc(GL_LEQUAL); //Taki nieistotny szczegół związany z powyższym, można usunąć glHint(GL_PERSPECTIVE_CORRECTION_HINT,GL_NICEST); //tzw. korekcja, tekstura będzie "ładnie" nałożona glEnable(GL_CULL_FACE); //usuwanie wielokątów odwróconych tyłem do obserwatora. Stosowane w grach, //na razie można wyłączyć.

I to tyle niezbędnych ustawień. Teraz tylko trzeba załadować tekstury, których będziemy używać. W przykładzie są dwie: t0.bmp i t1.bmp.

Tu małe wyjaśnienie po co jest plik pomoc.cpp. W tym pliku znajdują się procedury ładujące bitmapę oraz ustawiające format pixeli. Na razie można je traktować jako coś co jest i nie ważne skąd się wzięło. Nie jest to potrzebne do zrozumienia programu.

Za załadowanie tekstur odpowiada fragment kodu:

bits = LoadDIBitmap("t1.bmp",&info); rgb = ConvertRGB(info, bits); glBindTexture(GL_TEXTURE_2D,1); // od tego momentu tekstura "t1.bmp" jest pod uchwytem 1 glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); glTexImage2D(GL_TEXTURE_2D, 0, 3, info->bmiHeader.biWidth, info->Header.biHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, rgb); free(info); free(bits); free(rgb);

Pewne fragmenty kodu powtarzają się w komunikacie WM_SIZE. Jest to niestety konieczne, ze względu na właściwość API, która "traci" pewne ustawienia przy wyświetlaniu okna (które traktuje jako zmianę rozmiarów).

Od tego momentu można zająć się już ciekawszymi sprawami.

4. Klawiatura

Podczas obsługi komunikatu WM_KEYDOWN rejestrujemy naciśnięcia kursorów (konkretnie zmieniamy pewne kąty, o których za chwilę), Entera (zmienia sposób renderowania) i Esc (wyjście z programu).

5. Wyjście z programu

I usuwamy ten którego używaliśmy:

wglDeleteContext(hRC);

6. Rendering

Czyli najważniejsza część programu.

Renderowanie jest realizowane podczas obsługi komunikatu WM_PAINT. Niektóre źródła podają, że można je włączyć do pętli obsługi komunikatów. Ma to zaletę w postaci zwiększenia szybkości (minimalnie). Wadą natomiast jest możliwość utraty niektórych zdarzeń np. naciśnięcia klawisza. Ja proponuję pozostać przy WM_PAINT.

W naszym programie za renderowanie odpowiada funkcja void RenderujX(void); gdzie X to nr od 0 do 3. Cztery funkcje renderujące na cztery różne sposoby.

Obsługa WM_PAINT wygląda tak:

Renderuj0(); //Renderuje funkcja 0 SwapBuffers(hDC); //tzw. przerzucenie buforów, mające zapobiec migotaniu obrazu.

Zajmijmy się teraz funkcją renderującą. Najprostsza jest Renderuj0, rysująca ładnie pokolorowany trójkąt:

void Renderuj0(void) {

Najpierw wyłączamy texturowanie:

glDisable(GL_TEXTURE_2D);

Teraz czyścimy bufory koloru i tzw Bufor Z:

glClearColor(0.50f, 0.50f, 0.50f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); glClear(GL_DEPTH_BUFFER_BIT);

Zerujemy macierz transformacji:

glLoadIdentity();

Sprawdzamy, czy kąty o które obrócimy trójkąt są w granicach <0, 360) stopni:

if(KatX<0.0f) KatX+=360.0f; if(KatX>=360.0f) KatX-=360.0f; if(KatY<0.0f) KatY+=360.0f; if(KatY>=360.0f) KatY-=360.0f;

Teraz ważna część. Chcemy obrócić trójkąt mniej więcej względem jego środka ciężkości o odpowiednie kąty KatX i KatY. W tym celu przesuwamy obserwatora do środka (plus/minus) trójkąta, obracamy i oddalamy obserwatora z powrotem. Tu należy zwrócić uwagę na ciekawą właściwość macierzy transformacji: transformacje Open GL należy przeprowadzać "od końca". Dlaczego ? Jak ktoś chce niech sobie pomnoży kilka macierzy i będzie wiedział. Dla naszych potrzeb wystarczy wiedzieć, że jeśli chcemy obiekt najpierw przybliżyć (glTranslate), a potem przekręcić (glRotate), to należy użyć: glRotate, glTranslate:

glTranslatef(0.0f,0.0f,-200.0f); glRotatef(KatY,1.0f,0.0f,0.0f); glRotatef(KatX,0.0f,1.0f,0.0f); glTranslatef(0.0f,0.0f,200.0f);

Teraz już tylko narysowanie trójkąta. W tym celu używamy "klamer" glBegin...glEnd, wewnątrz których umieszczamy wierzchołki trójkąta. Dodatkowo każdy wierzchołek kolorujemy innym kolorem:

glBegin(GL_TRIANGLES); glColor3f(1.0f, 0.0f, 0.0f); glVertex3f(150.0f,-150.0f,-200.0f); glColor3f(0.0f, 1.0f, 0.0f); glVertex3f(0.0f,150.0f,-200.0f); glColor3f(0.0f, 0.0f, 1.0f); glVertex3f(-150.0f,-150.0f,-200.0f); glEnd();

Na koniec informujemy Open GL o skończonym renderingu. Teraz niech się martwi akcelerator (albo ostatecznie procesor).

glFinish(); }

Funkcja Renderuj1 jest znacznie ciekawsza, przedstawia teksturowany trójkąt. Nowe elementy to: Włączenie texturownia:

glEnable(GL_TEXTURE_2D);

Włączenie textury pierwszej:

glBindTexture(GL_TEXTURE_2D,1);

I podanie współrzędnych nabitmapie dla każdego wierzchołka:

glTexCoord2f(0.0f,0.0f);

Funkcja Renderuj2 to połączenie obu poprzednich.

Funkcja Renderuj3 pokazuje efekt Light Map'owania, czyli nakładania na teksturę światła obliczonego wcześniej (efekt stosowany w grach 3D). Realizuje się to przez dwukrotne nałożenie tekstury (zwykłej + światło). W nowych kartach 3D (od VooDoo 2) robi się to w jednym przebiegu na raz, ale efekt jest ten sam.

Z nowych rzeczy występują funkcje mieszające nałożone tekstury:

glEnable(GL_BLEND); glBlendFunc(GL_DST_COLOR,GL_SRC_COLOR);

7. Co dalej?

Dalej niech każdy poeksperymentuje sam... Proponuję rozbudować program tak, żeby wyświetlał np. więcej wielokątów, jakiś sześcian, może prosty engine 3D w stylu Wolfa. Na podstawie tego kodu dużo da się zrobić.

8. Jak stąd daleko do Quake 3?

No cóż, to pytanie jest raczej bardziej śmieszne niż poważne, ale nie do końca... Funkcje renderujące w enginach 3D nie różnią się bardzo. Należy zauważyć, że obecnie każdy może bawić się w programowanie silniczka 3D korzystającego z akceleratora. W Quake 1 w renderingu programowym też jest funkcja rysująca trójkąt. Ile autorowi zajęło jej napisanie ? Miesiąc, dwa, albo więcej. Do tego konieczność stosowania asemblera... Straszne ! Open GL rozwiązuje to w kilku linijkach kodu.

9. Open GL kontra Direct 3D

Zalety GL:

  • Bardzo łatwy w porównaniu w D3D,
  • Nieobiektowy, GL to raczej konsola do grafiki,
  • Ma więcej bajerów graficznych niż D3D,
  • Lepiej działa na VooDoo,
  • Dużo opisów dostępnych w sieci.

Wady GL:

  • Brak funkcji więżących program ze sterownikiem,
  • Zaawansowane właściwości GL (np. multiteksturowanie) są zawarte w tzw. GL Extensions, co zmusza do dokładnego badania używanego sterownika.

D3D nie ma dwóch ostatnich wad, jest za to strasznie skomplikowany. Przeważnie jednak przydaje się znajomość obu, cóż takie czasy.

Powodzenia !

Tekst dodał:
Adam Sawicki
01.04.2006 16:54

Ostatnia edycja:
Adam Sawicki
01.04.2006 16:54
(+ 1 niepotwierdzonych zmian)

Kategorie:

Aby edytować tekst, musisz się zalogować.

# Edytuj Porównaj Czas Autor Rozmiar
#2 edytuj (poprz.) 29.03.2012 12:49 jorul 11.83 KB (-349)
#1 edytuj (bież.) 01.04.2006 16:54 Adam Sawicki 12.17 KB
Zwykły
Do sprawdzenia
Do akceptacji
  • Oskar L. (@oskar1233) 22 kwietnia 2008 18:02
    Bardzo ładny art.
  • maxestws (@maxestws) 17 lipca 2008 02:22
    Ta, tylko autor chyba bardzo nie lubi D3D (moze nie lubi bo nie umie?). I co to w ogole za stwierdzenie, ze ogl ma wiecej "bajerow graficznych" niz d3d? Do autora: jak nie znasz jakiegos API to po prostu go z niczym nie porownuj, a nie wypisujesz takie glupotki. A potem szerza sie nieprawdziwe plotki
  • ~cunder 12 sierpnia 2008 17:53
    i mógłbyś sprawdzać pisownię w słowniku. "wykożystywać" !
  • Piotr Karkut (@Kiro) 19 listopada 2008 18:18
    Nieobiektowość to zaleta? Jak dla kogo...
  • Oskar L. (@oskar1233) 29 listopada 2008 14:58
    kiro: dla mnie na przykład ;]
  • xivrox (@xivrox) 31 grudnia 2008 21:28
    obiekty rzondzom!
  • RedHot (@RedHot) 11 stycznia 2009 18:40
    Lepiej działa na Voodoo xD <3
  • ~Maverick 26 lutego 2009 14:28
    Chyba panowie macie jakies problemy. Czlowiek zrobil bardzo dobra robote. Przejrzysty opis. Przykladowe porownanie. Wiec nie wiem co wam przeszkadza. Jak jestescie takimi specami to po co chodzicie po Necie i czytacie krotkie artykuły wprowazające. Odpalajcie edutory zbierajcie zespol i trzaskajcie sobie zaawansowane aplikacje zamiast negowac czyjas prace. No chyba, ze nie potraficie.
  • Dawid Ciosek (@dawidciosek) 21 maja 2011 12:41
    Wszystko ok tylko gdyby biblioteki .dll były łatwiej dostępne
  • Napisz komentarz:
    Aby dodać swój komentarz, musisz się zalogować.
Licencja Creative Commons

Warsztat używa plików cookies. | Copyright © 2006-2017 Warsztat · Kontakt · Regulamin i polityka prywatności
build #ff080b4740 (Tue Mar 25 11:39:28 CET 2014)