OGL, rysująca maszyna stanu


W każdym tutorialu oraz książce jest napisane, że OpenGL jest maszyną stanu. Znaczy to nie mniej, nie więcej, że zanim zaczniemy coś rysować na monitorze, musimy określić w jakim stanie znajduje się … OGL? Sterownik? Karta graficzna? Chyba najbezpieczniej jest powiedzieć, w jaki sposób zostanie zmodyfikowana część pamięci odpowiedzialna za dany wycinek ekranu.

Punkt startowy

Czym charakteryzuje się taka maszyna stanu? Posiada ona określoną ilość zmiennych, które są modyfikowane w zależności od potrzeb. Najlepiej chyba będzie wytłumaczyć to na kodzie z poprzedniego wpisu, który posłużył do sprawdzenia, czy nagłówki i biblioteki współpracują z Visual Studio.

int main(int argc, char* argv[]){
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
    glutInitWindowSize(250, 250);
    glutInitWindowPosition(100, 100);
    glutCreateWindow("Taki mały test");
    init();
    glutDisplayFunc(display);
    glutMainLoop();
    return 0;
}

Zaczynając od początku funkcji wejściowej, glutInit(&argc, argv); jest przekazaniem do gluta 😀 parametrów z jakimi program został uruchomiony. Kolejna linia to określenie trybu w jakim będzie wyświetlane. W tym przypadku będziemy korzystać z pojedynczego bufora oraz przestrzeni kolorów RGB. Już w tym momencie jawnie zaczynamy ingerować w stan całej maszyny, którą jest OpenGL ponieważ ustawiamy odpowiednie flagi zależnie od naszych potrzeb. Na chwilę obecną ten zestaw jest wystarczający, lecz jednak wybór jest znacznie większy. Pełną listę dostępnych możliwości możesz znaleźć w dokumentacji pod tym adresem. Następne trzy polecenia to określenie rozmiaru okna, jego położenie względem prawego górnego rogu ekranu oraz nadanie mu tytułu wraz z utworzeniem i wyświetleniem.

To by było na tyle 🙂

I tak na prawdę to już jest działający program! Spełnia najbardziej podstawowe założenia aplikacji korzystającej z biblioteki OpenGL. A to, że prawie nic nie wyświetla i od razu się zamyka to tylko szczegół 🙂 Wystarczy jeszcze dodać windowsowe wykonanie zatrzymania programu, czyli system("pause"); i cieszyć się małym oknem wypełnionym bielą do momentu interakcji z konsolą, która jest widoczna w tle.

W jaki sposób widzimy

My jednak chcemy aby program robił coś więcej i ustawiamy mu kolejne zmienne. Zajmujemy się więc kolorem tła wraz ze sposobem wyświetlania zawartości w sposób ortograficzny, czyli bez perspektywy. Wykorzystujemy do tego własną funkcję.

void init(void){
    glClearColor(0.0, 0.0, 0.0, 0.0);

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(0.0, 1.0, 0.0, 1.0, -1.0, 1.0);
}

Na początku określamy kolor tła, a więc do zmiennej globalnej GL_COLOR_BUFFER_BIT przypisujemy odpowiednie wartość RGBA koloru czarnego za pomocą funkcji z linii 18.

Dalej deklarujemy którą macierz będziemy modyfikować, tj macierz projekcji. Służy ona do konwersji przestrzeni trójwymiarowej na obraz dwuwymiarowy wyświetlany na ekranie. Funkcja glLoadIdentity(); wczytuje macierz jednostkową o odpowiednim rozmiarze. Następnie modyfikujemy ją do wyświetlania ortograficznego, podając do funkcji glOrtho odpowiednie parametry: lewą, prawą, dolną, górną, bliższą oraz dalszą płaszczyznę obcinania. Sprowadza się to do podania wartości skrajnych dla wszystkich trzech osi, poza którymi obiekty nie będą renderowane.

Rysujemy

Następnie w linii nr 33 rejestrujemy funkcję, która będzie wyświetlała obiekty. Jest to jedna z kilkunastu funkcji, które możemy w ten sposób określić. Pełną listę znajdziesz ponownie w dokumentacji pod tym adresem.

void display(void){
    glClear(GL_COLOR_BUFFER_BIT);

    glColor3f(1.0, 1.0, 1.0);
    glBegin(GL_POLYGON);
        glVertex3f(0.25, 0.25, 0.0);
        glVertex3f(0.75, 0.25, 0.0);
        glVertex3f(0.75, 0.75, 0.0);
        glVertex3f(0.25, 0.75, 0.0);
    glEnd();

    glFlush();
}

Na samym początku czyścimy bufor zdefiniowanym wcześniej kolorem (linia nr 4). Następnie ustawiamy kolor (linia nr 6) którym chcemy rysować w buforze za pomocą przestrzeni RGB. Poszczególne składowe koloru mają wartości z przedziału [0;1]. Jeżeli mamy już wyczyszczone płótno oraz wybrany kolor to możemy przystąpić do rysowania. Zaczynamy od określenia w jakim trybie będziemy malować oraz jednocześnie informujemy sterownik, że zaczynamy rysować(linia nr 7). W tym wypadku będziemy rysować wielokąt oparty na czterech wierzchołkach (linie nr 8-11). Każdy punkt znajduje się w trójwymiarowej przestrzeni, więc musimy podać kolejno współrzędne X, Y, oraz Z, co odpowiada położeniu na odpowiednich osiach. Wielokąt posiada on tę cechę, że jego wnętrze jest wypełnione kolorem, wierzchołki łączone są w kolejności w jakiej zostały podane, ilość wierzchołków jest nie mniejsza od 1 oraz pierwszy i ostatni wierzchołek są połączone. Nie jesteśmy oczywiście ograniczeni do wielokątu. Pełną listę możliwych trybów rysowania jak zawsze znajdziemy na odpowiedniej stronie dokumentacji. Zaś jak wyglądają odpowiednio figury narysowane w każdym z nich przedstawione są na zdjęciu poniżej.

Podajemy więc współrzędne wszystkich wierzchołków figury (linie nr 8-11) oraz informujemy, że przestaliśmy rysować (linia nr 12). Na samym końcu pozostaje upewnić się, że wszystko zostało wyświetlone na ekranie (linia nr 14).

Pozostaje tylko w funkcji main(void); wywołać przetwarzanie zdarzeń przez glut glutMainLoop();.

Na koniec jeszcze dodam, że jeżeli przed narysowaniem dowolnego wierzchołka zmienimy aktualny kolor, to w danym punkcie będzie od dokładnie taki jak został podany. Natomiast na obszarze pomiędzy aktualnie rysowanym wierzchołkiem a wszystkimi z nim sąsiadującymi, będzie łagodnie przechodził w kolory w nich zadeklarowane. Zachęcam do sprawdzenia samemu. Na przykład spróbuj narysować trójkąt pokazany niżej. Niżej jest podana funkcja rysująca, jednak zalecam zobaczenie jej w ostateczności.

void display(void){
	glClear(GL_COLOR_BUFFER_BIT);

    glBegin(GL_TRIANGLES);
	glColor3f(1.0, 0.0, 0.0); glVertex3f(0.0, 0.0, 0.0);
	glColor3f(0.0, 1.0, 0.0); glVertex3f(1.0, 0.0, 0.0);
	glColor3f(0.0, 0.0, 1.0); glVertex3f(0.5, 1.0, 0.0);
    glEnd();

	glFlush();
}

Pamiętaj, że funkcja glOrtho określa granice rysowania, oraz sprawia, że rysowanie dla różnych wartości Z punktu, na chwilę obecną nic nie zmieniają poza wyjściem części figury poza obszar rysowania.

W następnym wpisie opiszę kilka funkcji jakie dodatkowo możemy zarejestrować i są przydatne. Oczywiście możecie zadawać pytania oraz proponować kolejne tematy w komentarzach. Wszystkie zmiany w kodzie są wysyłane do repozytorium na github. Tak więc do następnego wpisu!

Ciao 🙂

Reklamy

Skomentuj

Wprowadź swoje dane lub kliknij jedną z tych ikon, aby się zalogować:

Logo WordPress.com

Komentujesz korzystając z konta WordPress.com. Wyloguj / Zmień )

Zdjęcie z Twittera

Komentujesz korzystając z konta Twitter. Wyloguj / Zmień )

Zdjęcie na Facebooku

Komentujesz korzystając z konta Facebook. Wyloguj / Zmień )

Zdjęcie na Google+

Komentujesz korzystając z konta Google+. Wyloguj / Zmień )

Connecting to %s