![]() |
Autor artykułu: mgr Jerzy Wałaszek, wersja1.0 |
©2011 mgr
Jerzy Wałaszek
|
Biblioteka OpenGL (Open Graphic Library - Otwarta Biblioteka Graficzna) zawiera funkcje, które umożliwiają tworzenie zaawansowanej grafiki trójwymiarowej. Programy napisane pod tę bibliotekę można szybko przenosić na inne platformy, np. do systemu Linux.
Zanim zaczniemy tworzyć jakąkolwiek grafikę 3D, musimy utworzyć odpowiedni projekt w środowisku Borland C++ Builder, który posłuży za szablon przyszłych projektów. W tym celu utwórz projekt, który zawiera pojedynczą formę i umieść na niej komponent Timer (z palety System). Następnie ustaw własności wg poniższej listy:
Form1
Caption = Grafika OpenGL
ClientHeight = 512
ClientWidth = 512
Name = frm3D
Position = poScreenCenter
Timer1
Name = tmrAnimate
Zapisz projekt na dysku. Nadaj mu nazwę glprj. Moduł zapisz pod nazwą glunit.
Do katalogu projektowego skopiuj poniższe dwa pliki:
Dodaj do projektu plik glaux.lib. W tym celu wybierz z menu opcje Project→Add to Project.., w oknie dialogowym wybierz katalog projektowy, następnie na dole wybierz pliki typu Library files lib., wskaż plik glaux.lib i zatwierdź go przyciskiem Otwórz.
Uwaga
Teraz przystąpimy do tworzenia kodu. Wciśnij klawisz F12, aby przejść do edytora. Następnie naciśnij Ctrl+F6, aby do edytora załadować plik nagłówkowy modułu glunit.h. Pod dyrektywami #include dopisz:
#ifndef glunitH
#define glunitH
#include <Classes.hpp>
#include <Controls.hpp>
#include <StdCtrls.hpp>
#include <Forms.hpp>
#include <ExtCtrls.hpp>
#include <gl/gl.h>
#include <gl/glu.h>
#include <gl/glaux.h>
#include <float.h>
//---------------------------------------------------------------------------
class Tfrm3D : public TForm
{
__published: // IDE-managed Components
Teraz w klasie obiektu dodajemy kilka definicji w sekcjach private i public:
private: // User declarations HDC hdc; HGLRC hrc; int PixelFormat; public: // User declarations __fastcall Tfrm3D(TComponent* Owner); void __fastcall SetPixelFormatDescriptor(); void __fastcall SetupRC(); }; //--------------------------------------------------------------------------- extern PACKAGE Tfrm3D *frm3D; //--------------------------------------------------------------------------- #endif
Naciśnij ponownie Ctrl+F6, aby w oknie edytora pojawił się kod modułu glunit.cpp. W konstruktorze klasy umieść kod:
//---------------------------------------------------------------------------
__fastcall Tfrm3D::Tfrm3D(TComponent* Owner)
: TForm(Owner)
{
_control87(MCW_EM, MCW_EM);
}
//---------------------------------------------------------------------------
Teraz musimy wpisać do modułu kilka funkcji pomocniczych - nie przejmuj się, jeśli nie rozumiesz ich przeznaczenia w tym momencie. Są one potrzebne do ustawienia parametrów biblioteki OpenGL w środowisku Borland C++ Builder. Funkcje umieść na końcu modułu.
//---------------------------------------------------------------------------
void __fastcall Tfrm3D::SetPixelFormatDescriptor()
{
PIXELFORMATDESCRIPTOR pfd = {
sizeof(PIXELFORMATDESCRIPTOR),
1,
PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER,
PFD_TYPE_RGBA,
24,
0,0,0,0,0,0,
0,0,
0,0,0,0,0,
32,
0,
0,
PFD_MAIN_PLANE,
0,
0,0,0
};
PixelFormat = ChoosePixelFormat(hdc, &pfd);
SetPixelFormat(hdc, PixelFormat, &pfd);
}
//---------------------------------------------------------------------------
void __fastcall Tfrm3D::SetupRC()
{
glClearColor(0,0,0,0);
glClear(GL_COLOR_BUFFER_BIT);
glFlush();
}
//---------------------------------------------------------------------------
Zadaniem funkcji SetPixelFormatDescriptor jest przygotowanie Windows do rysowania za pomocą biblioteki OpenGL na obiekcie Canvas okna aplikacji.
Funkcja SetupRC ustawia kolor tła okna i wypełnia tym kolorem bufor koloru biblioteki OpenGL.
Reszta niezbędnych funkcji to funkcje obsługi zdarzeń formy oraz komponentu Timer. Przypominam, że funkcję obsługi zdarzenia tworzy się w okienku Object Inspector na zakładce Events przez dwukrotne kliknięcie myszką po prawej stronie nazwy zdarzenia. Wtedy środowisko tworzy szablon odpowiedniej funkcji. Należy jedynie wypełnić jej treść.
Utwórz funkcję obsługi zdarzenia OnCreate dla formy i wpisz poniższy kod:
//---------------------------------------------------------------------------
void __fastcall Tfrm3D::FormCreate(TObject *Sender)
{
hdc = GetDC(Handle);
SetPixelFormatDescriptor();
hrc = wglCreateContext(hdc);
wglMakeCurrent(hdc, hrc);
SetupRC();
}
//---------------------------------------------------------------------------
Utwórz funkcję obsługi zdarzenia OnDestroy i wpisz poniższy kod:
//---------------------------------------------------------------------------
void __fastcall Tfrm3D::FormDestroy(TObject *Sender)
{
ReleaseDC(0,hdc);
wglMakeCurrent(hdc, NULL);
wglDeleteContext(hrc);
}
//---------------------------------------------------------------------------
Nasz szablon będzie obsługiwał zmianę rozmiaru okna. Dlatego utwórz funkcję obsługi zdarzenia onResize i wprowadź do niej poniższy kod:
//---------------------------------------------------------------------------
void __fastcall Tfrm3D::FormResize(TObject *Sender)
{
glViewport(0, 0, ClientWidth, ClientHeight); //
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0f,(GLfloat)ClientWidth/(GLfloat)ClientHeight,0.1f,300.0f);
glMatrixMode(GL_MODELVIEW);
glClearColor(0.0f, 0.0f, 0.0f, 0.0f); // kolor tła
glEnable(GL_DEPTH_TEST); // włącza bufor głębokości
glDepthFunc(GL_LESS);
glEnable(GL_CULL_FACE); // włącza opcję eliminacji ścian
glFrontFace(GL_CW); // ściany o wierzchołkach ułożonych zgodnie z ruchem wskazówek
// zegara będą traktowane jako zwrócone przodem
glCullFace(GL_BACK); // pomija rysowanie ścian odwróconych tyłem
}
//---------------------------------------------------------------------------
Ostatnie zdarzenie odnosi się do komponentu tmrAnimate (Timer). Kliknij jego nazwę w oknie Object TreeView. Następnie utwórz funkcję obsługi zdarzenia onTimer i wpisz do niej poniższy kod:
//---------------------------------------------------------------------------
void __fastcall Tfrm3D::tmrAnimateTimer(TObject *Sender)
{
tmrAnimate->Enabled = false; // blokujemy timer
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity(); // zerujemy przekształcenia
// Tutaj umieszczamy program dla OpenGL
glTranslatef(0.0f,0.0f,-6.0f);
glBegin(GL_TRIANGLES); // rysujemy trójkąt
glVertex2f( 0.0f, 1.0f);
glVertex2f( 1.0f,-1.0f);
glVertex2f(-1.0f,-1.0f);
glEnd();
// Koniec kodu dla OpenGL
SwapBuffers(hdc);
tmrAnimate->Enabled = true; // odblokowujemy timer
}
//---------------------------------------------------------------------------
Wyjaśnienia wymaga blokowanie Timera. Otóż może się zdarzyć, że na wolniejszym komputerze obsługa zdarzenia onTimer będzie dłuższa niż 20 ms. Wtedy następne przerwanie wystąpiłoby w trakcie tworzenia sceny i zniszczyłoby efekty całej naszej pracy. Aby temu zapobiec, funkcja obsługująca zdarzenie onTimer blokuje Timer na samym początku swego działania i odblokowuje go tuż przed zakończeniem.
Kod dla biblioteki OpenGL będziemy umieszczali w podanym miejscu wewnątrz funkcji obsługi zdarzenia onTimer. Przykładowy kod, który teraz tam umieściliśmy, rysuje biały trójkąt. Dokładniej omówimy to w dalszej części zajęć.
Sprawdź projekt, kompilując go i uruchamiając. Jeśli wszystko jest w porządku, powinieneś otrzymać czarne okno z białym trójkątem. Przy zmianie rozmiaru okna trójkąt też odpowiednio zmienia wymiary.

Teraz na podstawie tego projektu utworzymy szablon, który posłuży nam za punkt startowy dla przyszłych projektów. Z menu wybierz opcję Project→Add to Repository. W oknie dialogowym dodawania do składu wpisz:

Pamiętaj, aby nie usuwać z dysku katalogu z tym projektem, ponieważ zawiera on szablon. Aby przetestować ten szablon, utwórz na dysku nowy katalog projektowy, zamknij wszystkie projekty (opcja menu File→Close All), następnie wybierz File→New→Other..., w oknie dialogowym New Items wybierz zakładkę Projects.

Następnie zaznacz Projekt OpenGL i kliknij OK. W oknie dialogowym Select Directory wejdź do katalogu (Uwaga: nie wystarczy go wskazać, musi być otwarty), w którym ma zostać utworzony projekt i kliknij OK. Na podstawie naszego szablonu zostanie utworzona kopia projektu, w której znajdą się już wszystkie pliki. Jesteś gotowy do rozpoczęcia nauki programowania biblioteki OpenGL.

Układ współrzędnych w przestrzeni trójwymiarowej posiada trzy wzajemnie prostopadłe do siebie osie: OX, OY i OZ. Każdy wierzchołek v (ang. vertex) posiada w tym układzie trzy współrzędne vx, vy i vz, które jednoznacznie określają jego położenie w przestrzeni trójwymiarowej.

Jednostka odległości, wg której określane są te współrzędne, jest umowną liczbą, która zależy od ustawień początkowych w OpenGL. Ustawienia widoku w naszej aplikacji dokonywane są wewnątrz obsługi zdarzenia onResize. Znajduje się tam wywołanie funkcji:
gluPerspective(45.0f,(GLfloat)ClientWidth/(GLfloat)ClientHeight,0.1f,300.0f);
Ustawia ona "sposób patrzenia" na tworzoną scenę. Pierwszy parametr, 45.0f, tzw. określa kąt w stopniach ostrosłupa widzenia. Większy kąt obejmie więcej przestrzeni, lecz spowoduje efekt rybiego oka, czyli zniekształcenia perspektywiczne. Możesz sobie później poeksperymentować z tymi parametrami.
Kolejny parametr określa współczynnik kształtu prostokąta widzenia. Jest to stosunek szerokości do wysokości obszaru płótna Canvas. Zwróć uwagę, że przed podzieleniem oba parametry zostają przekonwertowane na postać GLfloat, czyli na liczby zmiennoprzecinkowe typu float. Bez tej konwersji komputer wykonałby dzielenie całkowite, a wynikiem byłoby 1 lub zero, w zależności co większe, wysokość czy szerokość okna.
Ostatnie dwa parametry, 0.1f i 300.0f, to tzw. głębia bufora wyświetlania. Punkty będą rysowane, jeśli ich współrzędne z będą się zawierały w zakresie od -0.1 do -300. Punkty bliższe i dalsze nie będą rysowane.
Współrzędne w OpenGL są liczbami zmiennoprzecinkowymi. Ponieważ oś OZ jest skierowana w kierunku obserwatora, to wierzchołki o współrzędnej z większej są bliżej obserwatora od wierzchołków o współrzędnej z mniejszej.
Układ współrzędnych można przesuwać względem położenia obserwatora przy pomocy funkcji
glTranslatef(dx,dy,dz);
Funkcja ta przyjmuje trzy parametry typu float, które definiują przesunięcie odpowiednio względem osi bieżącego układu. Poeksperymentuj z parametrami tej funkcji w programie.
glBegin(typ) |
– | rozpoczęcie rysowania. Parametr typ określa rodzaj rysowanego obiektu. |
glEnd() |
– | zakończenie rysowania |
Obiekty zawsze rysowane są w bieżącym układzie współrzędnych – jeśli ten układ przesuniesz za pomocą glTranslatef() (lub innych, które poznamy później), to rysowany obiekt będzie przesunięty. Przesunięcie układu współrzędnych nie wpływa na wcześniej narysowane punkty.
Do rysowania punktów wykorzystujemy funkcję ogólną glVertex##(). Literkami ## oznaczyliśmy rodzaj funkcji. OpenGL umożliwia definiowanie współrzędnych na wiele różnych sposobów. Aby nie powodować na początku zbytniego zamieszania, umówmy się, że będziemy korzystali z dwóch rodzajów funkcji:
glVertex2f(x,y) |
– | określa współrzędne punktu na płaszczyźnie OXY, Dla takiego wierzchołka współrzędna z jest równa 0. |
glVertex3f(x,y,z) |
– | określa współrzędne punktu w przestrzeni OXYZ. |
Napiszemy teraz prosty kod, który narysuje na płaszczyźnie OXY cztery punkty w narożnikach kwadratu o boku 2 ze środkiem w środku układu współrzędnych. Kod wprowadzamy do funkcji obsługi zdarzenia on|Timer dla tmrAnimarte w podanym miejscu, o ile nie zostanie wyraźnie napisane inaczej.
// Tutaj umieszczamy program dla OpenGL
glTranslatef(0.0f,0.0f,-3.0f); // przesuwamy układ w tył o 3 jednostki
glBegin(GL_POINTS); // rysujemy punkty w narożnikach kwadratu
glVertex2f( 1.0f, 1.0f); // v1
glVertex2f( 1.0f,-1.0f); // v2
glVertex2f(-1.0f,-1.0f); // v3
glVertex2f(-1.0f, 1.0f); // v4
glEnd();
// Koniec kodu dla OpenGL

Punkty są malutkie. Możemy je powiększyć za pomocą funkcji:
void glPointSize(GLfloat size);
Parametr size określa wielkość punktu. Nie wszystkie wielkości są dostępne w OpenGL. Dla środowiska Windows można przyjąć zakres od 0.5 do 10.0 z krokiem co 0.125. Wywołanie funkcji wstaw przed glBegin() dla wszystkich rysowanych punktów.
// Tutaj umieszczamy program dla OpenGL
glTranslatef(0.0f,0.0f,-6.0f); // przesuwamy układ w tył o 3 jednostki
glPointSize(10.0f); // duże punkty
glBegin(GL_POINTS); // rysujemy punkty w narożnikach kwadratu
glVertex2f( 1.0f, 1.0f); // v1 o wielkości 10
glVertex2f( 1.0f,-1.0f); // v2 o wielkości 10
glVertex2f(-1.0f,-1.0f); // v3 o wielkości 10
glVertex2f(-1.0f, 1.0f); // v4 o wielkości 10
glEnd();
// Koniec kodu dla OpenGL

Punkty są zawsze rysowane w takiej wielkości, jaka została ustawiona przed wywołaniem glBegin(). Jeśli zatem chcesz otrzymać punkty o różnych wielkościach, to musisz je rysować w osobnych blokach glBegin()...glEnd().
// Tutaj umieszczamy program dla OpenGL
glTranslatef(0.0f,0.0f,-3.0f); // przesuwamy układ w tył o 3 jednostki
glPointSize(10.0f);
glBegin(GL_POINTS);
glVertex2f( 1.0f, 1.0f); // v1 o wielkości 10
glEnd();
glPointSize(5.0f);
glBegin(GL_POINTS);
glVertex2f( 1.0f,-1.0f); // v2 o wielkości 5
glEnd();
glPointSize(2.0f);
glBegin(GL_POINTS);
glVertex2f(-1.0f,-1.0f); // v3 o wielkości 2
glEnd();
glPointSize(1.0f);
glBegin(GL_POINTS);
glVertex2f(-1.0f, 1.0f); // v4 o wielkości 1
glEnd();
// Koniec kodu dla OpenGL

Kolejny przykład będzie rysował punkty algorytmicznie, tak aby wypełniały one sześcian. Dodamy również ruch przez określenie przesunięcia w osi OX i OY układu współrzędnych przed rozpoczęciem rysowania punktów. Przesunięcie to będzie się zmieniało przy każdym przerwaniu onTimer, co w efekcie da wrażenie ruchu figury. Wprowadź kod dla OpenGL:
// Tutaj umieszczamy program dla OpenGL
static GLfloat Tx = -2; // przesunięcie w osi OX
static GLfloat Ty = -2; // przesunięcie w osi OY
static GLfloat dTx = 0.02; // przyrost w osi OX
static GLfloat dTy = 0.03; // przyrost w osi OY
GLfloat x,y,z;
glTranslatef(Tx,Ty,-6.0f); // przesuwamy układ współrzędnych
// modyfikujemy przesunięcie dla następnego kadru animacji
Tx += dTx; if(Tx < -2 || Tx > 2) dTx = -dTx;
Ty += dTy; if(Ty < -2 || Ty > 2) dTy = -dTy;
glPointSize(2.0f); // wszystkie punkty o rozmiarze 2
glBegin(GL_POINTS);
for(x = -1; x <= 1; x += 0.25)
for(y = -1; y <= 1; y += 0.25)
for(z = -1; z <= 1; z += 0.25) glVertex3f(x,y,z);
glEnd();
// Koniec kodu dla OpenGL

Do określania kolorów punktów służy funkcja
glColor##()
Podobnie jak przy glVertex##(), tutaj również mamy wiele możliwości określenia kolorów. Na początek określmy tę funkcję jako:
| glColor3f(r,g,b); | – | Kolor jest definiowany przez trzy składowe,
które mogą przyjmować wartość od 0 do 1: r –
składowa czerwona (ang. Red) |
Funkcję glColor##() możesz umieszczać zarówno przed glBegin() jak i przed każdym wierzchołkiem. Poniższy kod rysuje nasz sześcian z różnymi kolorami punktów, które zależą od położenia punktu w przestrzeni. Poeksperymentuj z nim trochę.
// Tutaj umieszczamy program dla OpenGL
static GLfloat Tx = -2; // przesunięcie w osi OX
static GLfloat Ty = -2; // przesunięcie w osi OY
static GLfloat dTx = 0.02; // przyrost w osi OX
static GLfloat dTy = 0.03; // przyrost w osi OY
GLfloat x,y,z;
glTranslatef(Tx,Ty,-6.0f); // przesuwamy układ w tył o 6 jednostek
Tx += dTx; if(Tx < -2 || Tx > 2) dTx = -dTx;
Ty += dTy; if(Ty < -2 || Ty > 2) dTy = -dTy;
glPointSize(3.0f); // wszystkie punkty o rozmiarze 3
glBegin(GL_POINTS);
for(x = -1; x <= 1; x += 0.25)
for(y = -1; y <= 1; y += 0.25)
for(z = -1; z <= 1; z += 0.25)
{
glColor3f((x+1)/2,(y+1)/2,1-(y+1)/2);
glVertex3f(x,y,z);
}
glEnd();
// Koniec kodu dla OpenGL

glBegin(GL_LINES); glVertex##(...); // punkt startowy linii glVertex##(...); // punkt końcowy linii ... glEnd();
Poniższy przykład rysuje trzy pary skrzyżowanych linii. Wprowadź go w miejsce kodu rysującego punkty w sześcianie. Zwróć uwagę na sposób rysowania każdej z par – rysujemy jedną, przesuwamy układ współrzędnych i rysujemy drugą.
// Tutaj umieszczamy program dla OpenGL
static GLfloat Tx = -2; // przesunięcie w osi OX
static GLfloat Ty = -2; // przesunięcie w osi OY
static GLfloat dTx = 0.02; // przyrost w osi OX
static GLfloat dTy = 0.03; // przyrost w osi OY
int i;
glTranslatef(Tx,Ty,-6.0f); // przesuwamy układ w tył o 6 jednostek
Tx += dTx; if(Tx < -2 || Tx > 2) dTx = -dTx;
Ty += dTy; if(Ty < -2 || Ty > 2) dTy = -dTy;
for(i = 0; i < 3; i++)
{
glTranslatef(0.0f,0.0f,-1.0f); // przesuwamy układ o 1 w tył
glBegin(GL_LINES);
glVertex2f(-1.0f,-1.0f); // początek pierwszej linii
glVertex2f( 1.0f, 1.0f); // koniec pierwszej linii
glVertex2f(-1.0f, 1.0f); // początek drugiej linii
glVertex2f( 1.0f,-1.0f); // koniec drugiej linii
glEnd();
}
// Koniec kodu dla OpenGL

Kolory linii ustalamy za pomocą funkcji glColor##(), którą musimy umieścić przed wywołaniem funkcji glVertex##() definiującymi punkty krańcowe linii. W powyższym programie wprowadź zmianę w pętli:
for(i = 0; i < 3; i++)
{
glTranslatef(0.0f,0.0f,-1.0f); // przesuwamy układ o 1 w tył
glBegin(GL_LINES);
glColor3f(1.0f,0.0f,0.0f); // pierwsza linia czerwona
glVertex2f(-1.0f,-1.0f); // początek pierwszej linii
glVertex2f( 1.0f, 1.0f); // koniec pierwszej linii
glColor3f(0.0f,1.0f,0.0f); // druga linia zielona
glVertex2f(-1.0f, 1.0f); // początek drugiej linii
glVertex2f( 1.0f,-1.0f); // koniec drugiej linii
glEnd();
}

Jeśli umieścisz wywołanie glColor##() przed wywołaniem glVertex##() dla obu końców linii, to OpenGL będzie rysowało linię z płynnym przejściem kolorów:
W programie zmień zawartość pętli:
for(i = 0; i < 3; i++)
{
glTranslatef(0.0f,0.0f,-1.0f); // przesuwamy układ o 1 w tył
glBegin(GL_LINES);
glColor3f(1.0f,0.0f,0.0f); // początek czerwony
glVertex2f(-1.0f,-1.0f); // początek pierwszej linii
glColor3f(1.0f,1.0f,0.0f); // koniec żółty
glVertex2f( 1.0f, 1.0f); // koniec pierwszej linii
glColor3f(0.0f,1.0f,0.0f); // początek zielony
glVertex2f(-1.0f, 1.0f); // początek drugiej linii
glColor3f(0.0f,0.0f,1.0f); // koniec niebieski
glVertex2f( 1.0f,-1.0f); // koniec drugiej linii
glEnd();
}

Szerokość linii ustalamy za pomocą funkcji
glLineWidth(GLfloat width);
Szerokość może być w granicach od 0.5 do 10.0 z krokiem co 0.125 (czyli zupełnie tak samo jak dla wielkości punktów). Funkcję glLineWidth() umieszczamy przed blokiem glBegin() ... glEnd(), w którym jest rysowana linia. Jeśli chcesz mieć linie o różnych szerokościach, to musisz użyć dla każdej z nich osobnego bloku glBegin() ... glEnd(), a przed każdym z tych bloków określić szerokość linii (tak samo postępowaliśmy w przypadku punktów).
W programie zmień zawartość pętli:
for(i = 0; i < 3; i++)
{
glTranslatef(0.0f,0.0f,-1.0f); // przesuwamy układ o 1 w tył
glLineWidth(6.0f-2*i); // szerokość linii
glBegin(GL_LINES);
glColor3f(1.0f,0.0f,0.0f); // początek czerwony
glVertex2f(-1.0f,-1.0f); // początek pierwszej linii
glColor3f(1.0f,1.0f,0.0f); // koniec żółty
glVertex2f( 1.0f, 1.0f); // koniec pierwszej linii
glColor3f(0.0f,1.0f,0.0f); // początek zielony
glVertex2f(-1.0f, 1.0f); // początek drugiej linii
glColor3f(0.0f,0.0f,1.0f); // koniec niebieski
glVertex2f( 1.0f,-1.0f); // koniec drugiej linii
glEnd();
}

#include <math.h>
Następnie wprowadź kod do funkcji tmrAnimateTimer():
// Tutaj umieszczamy program dla OpenGL
static GLfloat Tx = -2; // przesunięcie w osi OX
static GLfloat Ty = -2; // przesunięcie w osi OY
static GLfloat dTx = 0.02; // przyrost w osi OX
static GLfloat dTy = 0.03; // przyrost w osi OY
int i;
glTranslatef(Tx,Ty,-10.0f); // przesuwamy układ w tył o 10 jednostek
Tx += dTx; if(Tx < -2 || Tx > 2) dTx = -dTx;
Ty += dTy; if(Ty < -2 || Ty > 2) dTy = -dTy;
glBegin(GL_LINE_STRIP); // rysowanie łamanych otwartych
// generujemy ciąg punktów spirali
for(i = 0; i < 200; i++) glVertex3f(cos(i/10.0),sin(i/10.0),i/50.0);
glEnd();
// Koniec kodu dla OpenGL

Następny program rysuje pięć okręgów jeden nad drugim w odległości co 0.5 jednostki na osi z.
// Tutaj umieszczamy program dla OpenGL
static GLfloat Tx = -2; // przesunięcie w osi OX
static GLfloat Ty = -2; // przesunięcie w osi OY
static GLfloat dTx = 0.02; // przyrost w osi OX
static GLfloat dTy = 0.03; // przyrost w osi OY
int i,j;
glTranslatef(Tx,Ty,-10.0f); // przesuwamy układ w tył o 10 jednostek
Tx += dTx; if(Tx < -2 || Tx > 2) dTx = -dTx;
Ty += dTy; if(Ty < -2 || Ty > 2) dTy = -dTy;
for(j = 0; j < 5; j++)
{
glTranslatef(0.0f,0.0f,0.5f); // przesuwamy się do przodu o 0.5 jednostki
glBegin(GL_LINE_LOOP); // rysowanie łamanych zamkniętych
for(i = 0; i < 40; i++) glVertex2f(cos(6.28 * (i/40.0)),sin(6.28 * (i/40.0)));
glEnd();
}
// Koniec kodu dla OpenGL

// Tutaj umieszczamy program dla OpenGL
static GLfloat Tx = -2; // przesunięcie w osi OX
static GLfloat Ty = -2; // przesunięcie w osi OY
static GLfloat dTx = 0.02; // przyrost w osi OX
static GLfloat dTy = 0.03; // przyrost w osi OY
glTranslatef(Tx,Ty,-6.0f); // przesuwamy układ w tył o 6 jednostek
Tx += dTx; if(Tx < -2 || Tx > 2) dTx = -dTx;
Ty += dTy; if(Ty < -2 || Ty > 2) dTy = -dTy;
glBegin(GL_TRIANGLES); // rysowanie trójkątów
glVertex2f( 0.0f, 0.0f); // pierwszy trójkąt
glVertex2f(-1.0f, 0.0f);
glVertex2f(-0.5f, 1.0f);
glVertex2f( 0.0f, 0.0f); // drugi trójkąt
glVertex2f( 1.0f, 0.0f);
glVertex2f( 0.5f,-1.0f);
glEnd();
// Koniec kodu dla OpenGL

Zmień zawartość bloku, aby dodać kolory:
glBegin(GL_TRIANGLES); // rysujemy trójkąty
glColor3f(1.0f,1.0f,0.0f);// żółty
glVertex2f( 0.0f, 0.0f); // pierwszy trójkąt
glVertex2f(-1.0f, 0.0f);
glVertex2f(-0.5f, 1.0f);
glColor3f(0.0f,1.0f,1.0f);// cyjan
glVertex2f( 0.0f, 0.0f); // drugi trójkąt
glVertex2f( 1.0f, 0.0f);
glVertex2f( 0.5f,-1.0f);
glEnd();

Jeśli kolor określisz przed każdym wierzchołkiem, to wnętrze trójkąta będzie kolorowane gradientowo.
glBegin(GL_TRIANGLES); // rysujemy trójkąty
glColor3f(1.0f,1.0f,0.0f);// żółty
glVertex2f( 0.0f, 0.0f); // pierwszy trójkąt
glColor3f(0.0f,1.0f,0.0f);// zielony
glVertex2f(-1.0f, 0.0f);
glColor3f(0.0f,0.0f,1.0f);// niebieski
glVertex2f(-0.5f, 1.0f);
glColor3f(1.0f,1.0f,0.0f);// żółty
glVertex2f( 0.0f, 0.0f); // drugi trójkąt
glColor3f(1.0f,0.0f,0.0f);// czerwony
glVertex2f( 1.0f, 0.0f);
glColor3f(0.0f,1.0f,1.0f);// cyjan
glVertex2f( 0.5f,-1.0f);
glEnd();

Trójkąty w programie znajdowały się na płaszczyźnie OXY. Nic jednakże nie stoi na przeszkodzie, aby były rysowane w przestrzeni 3D. Poniższy program rysuje trzy trójkąty, które tworzą ściany boczne czworościanu. Zwróć uwagę na kolejność określania wierzchołków trójkąta. Umówmy się na przyszłość, że będzie ona taka, aby patrząc na przód ściany, punkty były określane zgodnie z ruchem wskazówek zegara – jeśli będzie na odwrót, to OpenGL nie narysuje ściany. Zostało to określone w obsłudze zdarzenia onResize przy pomocy funkcji:
glEnable(GL_CULL_FACE); // włącza opcję eliminacji ścian
glFrontFace(GL_CW); // ściany o wierzchołkach ułożonych zgodnie z ruchem wskazówek
// zegara będą traktowane jako zwrócone przodem
glCullFace(GL_BACK); // pomija rysowanie ścian odwróconych tyłem
Opcja ta przyspiesza rysowanie sceny, ponieważ pomija ściany, które są odwrócone tyłem, a zatem niewidoczne dla obiektów pełnych (jeśli obiekty mają w ścianach dziury, przez które widać ich wnętrze, to pomijanie ścian należy wyłączyć). Więcej o tej opcji podamy na następnych zajęciach.
glBegin(GL_TRIANGLES); // rysujemy trójkąty
glColor3f(1.0f,1.0f,0.0f); // trójkąt żółty
glVertex3f( 0.0f, 1.0f, 0.0f);
glVertex3f( 1.0f,-1.0f, 0.0f);
glVertex3f( 0.0f, 0.0f, 1.0f);
glColor3f(0.0f,1.0f,0.0f); // trójkąt zielony
glVertex3f( 1.0f,-1.0f, 0.0f);
glVertex3f(-1.0f,-1.0f, 0.0f);
glVertex3f( 0.0f, 0.0f, 1.0f);
glColor3f(1.0f,0.0f,1.0f); // trójkąt purpurowy
glVertex3f(-1.0f,-1.0f, 0.0f);
glVertex3f( 0.0f, 1.0f, 0.0f);
glVertex3f( 0.0f, 0.0f, 1.0f);
glEnd();

// Tutaj umieszczamy program dla OpenGL
static GLfloat Tx = -2; // przesunięcie w osi OX
static GLfloat Ty = -2; // przesunięcie w osi OY
static GLfloat dTx = 0.02; // przyrost w osi OX
static GLfloat dTy = 0.03; // przyrost w osi OY
glTranslatef(Tx,Ty,-6.0f); // przesuwamy układ w tył o 6 jednostek
Tx += dTx; if(Tx < -2 || Tx > 2) dTx = -dTx;
Ty += dTy; if(Ty < -2 || Ty > 2) dTy = -dTy;
glBegin(GL_QUADS); // rysujemy czworoboki
glColor3f(1.0f,1.0f,0.0f); // czworobok czerwony
glVertex3f( 1.0f, 0.0f, 0.0f);
glVertex3f(-1.0f, 0.0f, 0.0f);
glVertex3f(-1.0f, 1.0f, 1.0f);
glVertex3f( 1.0f, 1.0f, 1.0f);
glColor3f(0.0f,1.0f,0.0f); // czworobok zielony
glVertex3f( 1.0f, 0.0f, 0.0f);
glVertex3f( 1.0f,-1.0f, 1.0f);
glVertex3f(-1.0f,-1.0f, 1.0f);
glVertex3f(-1.0f, 0.0f, 0.0f);
glEnd();
// Koniec kodu dla OpenGL

| Nazwa stałej | Opis |
GL_POINTS |
Rysuje punkty |
GL_LINES |
Rysuje linie |
GL_LINE_STRIP |
Rysuje łamaną otwartą |
GL_LINE_LOOP |
Rysuje łamaną zamkniętą |
GL_TRIANGLES |
Rysuje trójboczną ścianę |
GL_QUADS |
Rysuje czworoboczną ścianę |
Wewnątrz bloku glBegin() ... glEnd() używamy funkcji glVertex##() do określenia współrzędnych punktów, które tworzą prymitywy.
glVertex2f(x,y) |
– | określa współrzędne punktu na płaszczyźnie OXY, Dla takiego wierzchołka współrzędna z jest równa 0. |
glVertex3f(x,y,z) |
– | określa współrzędne punktu w przestrzeni OXYZ. |
Wielkość punktów określa funkcja:
void glPointSize(GLfloat size);
Parametr size może przyjmować wartości od 0.5 do 10.0 z krokiem co 0.125. Funkcję tę należy wywołać przed blokiem glBegin() ... glEnd().
Grubość linii określa funkcja:
glLineWidth(GLfloat width);
Parametr width może przyjmować wartości od 0.5 do 10.0 z krokiem co 0.125. Funkcję tę należy wywołać przed blokiem glBegin() ... glEnd().
Do określania kolorów służy funkcja
glColor3f(r,g,b); |
Kolor jest definiowany przez trzy składowe,
które mogą przyjmować wartość od 0 do 1: r –
składowa czerwona (ang. Red) |
Funkcję można wywoływać tuż przed wywołaniem glVertex##(). Jeśli figura posiada kilka wierzchołków, to kolor będzie rysowany gradientowo przy przejściu z jednego wierzchołka do drugiego.
Układ współrzędnych przesuwamy za pomocą funkcji:
glTranslatef(GLfloat dx, GLfloat dy, GLfloat dz);
Po przesunięciu układu współrzędnych punkty będą rysowana w nowym miejscu przestrzeni. Przesunięcie nie wpływa na punkty już narysowane w innym bloku glBegin() ... glEnd().
![]() | I Liceum Ogólnokształcące |
Pytania proszę przesyłać na adres email: i-lo@eduinf.waw.pl
W artykułach serwisu są używane cookies. Jeśli nie chcesz ich otrzymywać,
zablokuj je w swojej przeglądarce.
Informacje dodatkowe