OpenGL

rk7771

<font size="4">OpenGL - generowanie grafiki 3D.</span>

screen_kostka_opengl.jpg


Przykładowe kody źródłowe znajdują się w dziale Kody źródłowe -> Delphi:

Engine 3D OpenGL Kostka 3D OpenGL
Opis podstawowy. =========== OpenGL zaprojektowany został z myślą tworzenia różnego rodzaju aplikacji. Dostępny jest dla wszystkich najważniejszych platform w różnych konfiguracjach sprzętowych. Biblioteka niskiego poziomu OpenGL umożliwia generowanie zaawansowanej grafiki i jest wykorzystywana w komputerowym wspomaganiu projektowania czy grach. W szczególności można powiedzieć, iż OpenGL określa interfejs programowy udostępniający programiście możliwości graficzne platformy na której tworzona będzie aplikacja. W celu umożliwienia pełnej kontroli nad tworzoną grafiką i zwiększeniu uniwersalności OpenGL zawiera jedynie operacje niskiego poziomu. Operacje niskiego poziomu pozwalają stworzyć własną bibliotekę graficzną wysokiego poziomu. Przykładem biblioteki wysokiego poziomu może być GLU (OpenGL Utility Library), która jest dostarczana wraz z większością dystrybucji OpenGL. Biblioteka OpenGL związana jest z tworzeniem wyłącznie grafiki i w przeciwieństwie do DirectX nie umożliwia ona tworzenia operacji związanych z tworzeniem dźwięku, interakcją z użytkownikiem czy tworzenia interfejsu sieciowego. Od roku 1992 rozwój specyfikacji OpenGL prowadzony jest przez OpenGL Architecture Review Board (ARB), w skład której wchodzą firmy ATI, Compaq (obecnie HP Compaq), Evans & Sutherland, Hewlett-Packard, IBM, Intel, Intergraph, nVidia, Microsoft oraz Silicon Graphics. Sama specyfikacja OpenGL opracowana została natomiast przez firmę Silicon Graphics, Inc. (SGI) jako interfejs służący do tworzenia grafiki, który jest niezależny od platformy. Zadaniem ARB jest przygotowywanie specyfikacji OpenGL i tym samym dyktowanie funkcjonalności kolejnych dystrybucji interfejsu OpenGL tworzonych przez producentów. OpenGL wykorzystuje maszynę stanów, stany opisują natomiast sposób wykonywania operacji graficznych. Sama specyfikacja OpenGL zawiera zaś kilkaset funkcji udostępniających możliwości sprzętu graficznego. Korzystając z interfejsu programowego OpenGL można określać wiele aspektów maszyny stanów, takich jak na przykład: bieżący kolor, oświetlenie, sposób łączenia kolorów i tak dalej. Sposób tworzenia grafiki jest więc określony przez bieżącą konfigurację maszyny stanów. Zrozumienie znaczenia poszczególnych stanów maszyny umożliwia poprawne tworzenie aplikacji. Niewłaściwy wybór stanu skutkuje natomiast nieprzewidzianymi efektami operacji graficznych. Jądrem biblioteki OpenGL jest potok tworzonej grafiki, a uświadomienie sobie, iż wszystko, co jest widoczne na ekranie, stanowi rezultat wykonania szeregu operacji w potoku jest najważniejszą rzeczą. Większość operacji w potoku wykonywana jest automatycznie przez bibliotekę OpenGL. Bibliotekami uzupełniającymi OpenGL jest pakiet GLUT {OpenGL Utility Toolkit) zawierający zestaw pomocniczych bibliotek. Jest on dostępny dla najważniejszych platform. Biblioteki uzupełniające dają możliwość tworzenia menu, okien czy interfejsu interakcji z użytkownikiem. Są one niezależne od platformy dając możliwość łatwego przenoszenia między różnymi systemami operacyjnymi (np.: z Windows do Unix). Biblioteki GLUT są zupełnie wystarczające w przypadku tworzenia prostych aplikacji czy przykładów demonstracyjnych. Niedostarczają one jednak możliwości jakie oferuje system operacyjny. Implementacja OpenGL w środowisku Delphi. ============================= Krok pierwszy - dołączenie bibliotek do środowiska Delphi. ------------------------------------------------------------------------ Do prawidłowego działania OpenGL w Delphi niezbędne jest dołączenie plików pas, tj.: GL.pas, GLext.pas, GLU.pas, GLUT.pas. Są to biblioteki podstawowe wraz z bibliotekami rozszerzonymi. W celu dołączenia tekstur w formacie plików jpg do tworzonych brył można wykorzystać plik: textures.pas, natomiast wykorzystanie plików bmp wymaga dołączenia pliku: bmp.pas. Krok drugi - budowa struktury programu w Delphi. ------------------------------------------------------------- W nowym projekcie tworzonej aplikacji w delphi utworzyć należy procedury: tworzenia formy: FormCreate, aktywacji formy: FormActivate, obsługi zmiany wielkości formy: FormResize, rysowania formy: FormPaint, obsługi zegara: Timer1Timer, inicjalizacji maszyny stanu Open GL: GLInit, ustawienie formatu pikseli: setupPixelFormat, tworzenia grafiki: Draw. Procedury: FormCreate, FormActivate, FormResize, FormPaint oraz Timer1Timer tworzymy w object inspektorze. Procedury: GLInit, setupPixelFormat oraz Draw dodajemy ręcznie w kodzie źrodłowym. W sekcji uses dodajemy obsługę bibliotek OpenGl tj.: Gl, Glu, OpenGL oraz dodajemy pliki ładowania tekstur. Stosownie od preferencji: textures lub bmp. Do programu dodajemy również Timer w celu obsługi animacji. Wygląd schematu programu: ```delphi unit nazwa_unit; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, Gl, Glu, OpenGL, Textures, ExtCtrls; type Tprez_form = class(TForm) Timer1: TTimer; procedure Timer1Timer(Sender: TObject); procedure FormActivate(Sender: TObject); procedure FormPaint(Sender: TObject); procedure FormCreate(Sender: TObject); procedure GLInit(); procedure setupPixelFormat(DC:HDC); private { Private declarations } procedure Draw(); public { Public declarations } end; var prez_form: Tprez_form; implementation {$R *.dfm} procedure Tprez_form.FormCreate(Sender: TObject); begin //ustawienia startowe wywoływane podczas tworzenia formy end; procedure Tprez_form.FormActivate(Sender: TObject); begin // aktywacja formy SetupPixelFormat(); //wywołanie procedury ustawiającej format pikseli GLInit; //wywołanie procedury inicjalizującej Open GL end; procedure Tprez_form.FormPaint(Sender: TObject); begin draw(); // wywołanie procedury rysującej end; procedure Tprez_form.GLInit(); begin //inicjalizacja maszyny stanu Open GL //a w szczególności określenie macierzy //rzutowania ? glMatrixModel, itp. end; procedure Tprez_form.setupPixelFormat(DC:HDC); const //określenie stałych var //określenie zmiennych begin //ustawienie formatu pikseli end; procedure Tprez_form.Draw(); begin //procedura rysująca end; procedure Tprez_form.Timer1Timer(Sender: TObject); begin //obsługa zegara Draw(); //wywołanie procedury rysującej end; ``` Krok trzeci - uzupełnienie struktury programu funkcjami. --------------------------------------------------------------------- Przed uzupełnieniem struktury programu funkcjami, nadmienić trzeba, iż w sekcji uses dodane zostały odwołania do bibliotek OpenGL, tj.: Gl, Glu, OpenGL. Dodano również plik textures.pas w celu ładowania tekstur z plików jpg. Zamiast pliku textures.pas dołączyć można bmp.pas co umożliwi ładowanie tekstur z plików bmp. Nie jest to jednak zasadne ze względu na wielkości bitmap. Ustawienia startowe wywoływane podczas tworzenia formy (FormCreate) ----------------------------------------------------------------------------------------- W momencie gdy formularz jest tworzony (czy to w sposób automatyczny, czy też ręczny) uaktywnianych zostaje kilka zdarzeń w skład których wchodzą: zdarzenie OnCreate - informujące o tworzeniu formy, zdarzenie OnShow - informujący o wyświetleniu formy na ekranie, zdarzenie OnActivate - które sygnalizuje, że dany formularz został właśnie wybrany spośród pozostałych formularzy ujętych w programie, zdarzenia OnResize oraz OnPaint - które aktywowane są przy zmianie, jak i na początku tworzenia formularza. W procedurze FormCreate ująć należy funkcje uruchamiane podczas tworzenia formy. W skład podstawowych funkcji zaliczyć można: podstawienie wartości do zmiennych statycznych (np.: ścieżka programu/), ustawienie wyglądu formy (wielkość, pozycja, ikony systemowe w pasku, nazwa formy), ustawienia dla timera ? interwał, Przykładowa postać procedury FormCreate obsługująca zdarzenie OnCreate: ```delphi procedure Tprez_form.FormCreate(Sender: TObject); begin sc_programu:=ExtractFilePath(ParamStr(0)); //obsługa ikon systemowych w pasku tytułowym prez_form.BorderIcons := [biSystemMenu]; //pozostawienie ikony[x] zamykającej program //pusta wartość [] powoduje usunięcie wszystkich //ikon z paska tytułowego formy //ustawienie na false wartości prez_form.Scaled umożliwia //zmianę jej wielkości w kodzie źródłowym - funkcja którą //trzeba zmienić od wersji Delphi wyższej niż 7 prez_form.Scaled := false; //ustawienia wielkości formy prez_form.Width := Screen.Width-100; prez_form.Height := Screen.Height-100; //ustawienia pozycji formy na ekranie prez_form.Top := 0; prez_form.Left := 0; //zmiana interwału dla komponentu Timer Timer1.Interval := 100; end; ``` W celu ujednolicenia i braku migania formy podczas jej ładowania wskazane jest powtórzyć ustawienia dla formy obejmujące jej pozycję na ekranie w procedurze FormActivate, tj.: ```delphi prez_form.Scaled := false; prez_form.Width := Screen.Width-100; prez_form.Height := Screen.Height-100; prez_form.Top := 0; prez_form.Left := 0; ``` Ustawienie prez_form.Scaled := false dotyczy Delphi wyższych niż wersja 7. Od wersji 7 w dół ustawienie to nie jest wymagane. Aktywacja formy (FormActivate). ----------------------------------------- Procedura aktywacji formy FormActivate (obsługi zdarzenia OnActivate) oprócz wspomnianych powyżej ustawień pozycji formy na ekranie musi zawierać odwołania do procedur SetupPixelFormat oraz GLInit. Odpowiedzialne są one w szczególności za: procedura SetupPixelFormat - ustawienie formatu pikseli, GLInit - inicjalizację maszyny stanów OpenGL. Dodatkowo procedura aktywacji formy zawierać musi kontekst tworzenia grafiki oraz kontekst urządzenia, które ujęte są: ```delphi var DC:HDC; RC:HGLRC; begin DC:=GetDC(Handle); RC:=wglCreateContext(DC); wglMakeCurrent(DC, RC); end; ``` Cała, minimalna, postać procedury aktywacji formy (FormActivate) wyglądać powinna jak na poniższym przykładzie: ```delphi procedure Tprez_form.FormActivate(Sender: TObject); var DC:HDC; RC:HGLRC; begin prez_form.Scaled := false; //ustawienia wielkości formy prez_form.Width := Screen.Width-100; prez_form.Height := Screen.Height-100; //ustawienia pozycji formy na ekranie prez_form.Top := 0; prez_form.Left := 0; DC:=GetDC(Handle); SetupPixelFormat(DC); //wywołanie procedury odpowiedzialnej //ustawienie formatu pikseli RC:=wglCreateContext(DC); wglMakeCurrent(DC, RC); GLInit; //wywołanie procedury inicjalizującej //maszynę stanów OpenGL end; ``` Obsługa malowania na formularzu (FormPaint). --------------------------------------------------------- Po pierwszym uruchomieniu programu niezbędne jest obsłużenie procedury malowanie na formularzu: FormPaint (obsługującej zdarzenie OnPaint). Związane jest to z przyczyną zastosowanej przez Windows domyślnej procedury odświeżania okien. Po uruchomieniu programu należy wymusić na systemie Windows operację malowania utrwalając efekt rysowania grafiki trójwymiarowej na formie. Procedura malowania po uruchomieniu programu zawierać powinna tylko wywołanie głównej procedury rysowania grafiki trójwymiarowej, tj.: w naszym przypadku procedury Draw. Przedstawia to poniższy przykład: ```delphi procedure Tprez_form.FormPaint(); begin Draw(); end; ``` Obsługa zdarzenia OnTimer komponentu Timer (Timer1Timer). ----------------------------------------------------------------------------- W procedurze obsługi zdarzenia OnTimer komponentu Timer należy zastosować funkcję związane z ruchem, np.: obracającego się sześcianu który mógłby być uzupełniony wypełnionymi teksturami. Należy również umieścić w niej wywołanie głównej procedury tworzącej grafikę trójwymiarową, tj.: w naszym przypadku Draw(). Konstrukcja procedury wyglądać może: ```delphi procedure Tprez_form.Timer1Timer(Sender: TObject); begin { funkcje obliczające nowe wartości zmiennych związane z ruchem czyli funkcjami wykorzystywanymi w procedurze Draw do przeprowadzenia obrotów, przesunięć jak np.: - glTranslatef(0.0,0.0, przesunięcie) - funkcja związana z przesunięciem dla której można obliczać w procedurze Timer1Timer wartość zmiennej przesuniecie - glRotatef(obr_poziom, 1, 0, 0) - funkcja związana z obrotem dla której można obliczać w procedurze Timer1Timer wartości zmiennej obr_poziom oraz innymi, np.: zmianą ustawienia oświetlenia, czasową zmianą intensywności mgły, czasem życia cząstek wykorzystywanych podczas opadu deszczu, śniegu, wybuchem itp. } //ponowne wywołanie głównej procedury tworzącej grafikę trójwymiarową //częstotliwość wywołań uzależniona jest od ustawionego interwału komponentu Timer1, //którego wartość została statycznie przypisana w procedurze FormCreate Draw(); end; ``` Ustawienie formatu pikseli (setupPixelFormat). --------------------------------------------------------- Format pikseli trzeba zawsze określić przed stworzeniem kontekstu tworzenia grafiki. Określić można na przykład tryb koloru, bufor głębi, liczbę bitów opisujących piksel czy sposób buforowania zawartości okna. Ustawienie formatu pikseli stanowi kolejne rozszerzenie interfejsu programowego Windows. W stałych należy określić strukturę TPIXELFORMATDESCRIPTOR: ```delphi const pfd:TPIXELFORMATDESCRIPTOR = ( //rozmiar struktury nSize:sizeof(TPIXELFORMATDESCRIPTOR); //zawsze wartość 1 nVersion:1; //znaczniki właściwości bufora pikseli dwFlags:PFD_SUPPORT_OPENGL or PFD_DRAW_TO_WINDOW or PFD_DOUBLEBUFFER; //typ danych piksela iPixelType:PFD_TYPE_RGBA; //liczba bitów piksela cColorBits:24; //liczba bitów koloru czerwonego oraz //przesunięcie bitów koloru czerwonego cRedBits:0; cRedShift:0; //liczba bitów koloru zielonego oraz //przesunięcie bitów koloru zielonego cGreenBits:0; cGreenShift:0; //liczba bitów koloru niebieskiego oraz //przesunięcie bitów koloru niebieskiego cBlueBits:0; cBlueShift:0; //liczba bitów alfa oraz //przesunięcie bitów alfa cAlphaBits:0; cAlphaShift:0; //liczba bitów bufora akumulacji cAccumBits: 0; //liczba bitów akumulacji czerni cAccumRedBits: 0; //liczba bitów akumulacji zieleni cAccumGreenBits: 0; //liczba bitów akumulacji błękitu cAccumBlueBits: 0; //liczba bitów akumulacji alfa cAccumAlphaBits: 0; //liczba bitów bufora głębi cDepthBits:16; //liczba bitów bufora powielania cStencilBits:0; //liczba buforów pomocniczych cAuxBuffers:0; //nie jest już wykorzystywany iLayerType:PFD_MAIN_PLANE; //liczba podkładanych i nakładanych jednostek bReserved: 0; //nie jest już wykorzystywany dwLayerMask: 0; //indeks podłożonej płaszczyzny dwVisibleMask: 0; //nie jest już wykorzystywany dwDamageMask: 0; ); ``` gdzie: nsize: opisuje rozmiar struktury przekazywanych za pomocą wskaźnika, służy do określenia wielkości pamięci zajmowanej przez strukturę. Umieszczenie w pierwszym polu umożliwia szybkie pobranie przez deferencję wskaźnika. Dwflags: określa właściwości bufora pikseli (PFD_DRAW_TO_WINDOW ? umożliwia tworzenie grafiki w oknie, PFD_SUPPORT_OPENGL ? umożliwia tworzenie grafiki opengl, PFD_DOUBLEBUFFER ? podwójne buforowanie /wyklucza się ze znacznikiem PFD_SUPPORT_GDI/, PFD_SWAP_LAYER_BUFFERS ? urządzenie może przełączać pojedyncze plany warstw z formatami pikseli o podwójnym buforowaniu /w przeciwnym razie wszystkie plany warstw przełączane są grupowo/; jeśli znacznik jest ustawiony, to dostępna jest funkcja wglSwapLayerBuffers, PFD_DEPTH_DONTCARE ? dla danego formatu pikseli może być wykorzystywany bufor głębi, PFD_DOUBLEBUFFER_DONTCARE ? piksele mogą być buforowane pojedynczo lub podwójnie), IPixelType: określa typ danych piksela (PFD_TYPE_RGBA ? piksele opisane w standardzie RGBA czyli dla każdego piksela określony jest kolor czerwony, zielony, niebieski oraz współczynnik alfa, PFD_TYPE_COLORINDEX ? piksele opisane są za pomocą wartości indeksu koloru), CcolorBits: opisuje liczbę bitów określających kolor piksela i może przyjmować wartości 8, 16, 24 i 32. W przypadku gdy karta grafiki nie umożliwia reprezantacji koloru pikseli za pomocą danej liczby bitów to przyjmowana jest jej największa możliwa wartość. W zmiennych należy określić: ```delphi pixelFormat : integer ``` a w samej procedurze przyporządkować wartość całkowitą indeksu dostępnego formatu pikseli: ```delphi pixelFormat := ChoosePixelFormat(DC, @pfd) ``` oraz sprawdzić wartość przypisania: ```delphi if (pixelFormat = 0) then exit; if (SetPixelFormat(DC, pixelFormat, @pfd) < TRUE) then exit; ``` Cała procedura setupPixelFormat(DC:HDC) wygląda następująco: ```delphi procedure Tprez_form.setupPixelFormat(DC:HDC); const pfd:TPIXELFORMATDESCRIPTOR = ( nSize:sizeof(TPIXELFORMATDESCRIPTOR); nVersion:1; dwFlags:PFD_SUPPORT_OPENGL or PFD_DRAW_TO_WINDOW or PFD_DOUBLEBUFFER; iPixelType:PFD_TYPE_RGBA; cColorBits:24; cRedBits:0; cRedShift:0; cGreenBits:0; cGreenShift:0; cBlueBits:0; cBlueShift:0; cAlphaBits:0; cAlphaShift:0; cAccumBits: 0; cAccumRedBits: 0; cAccumGreenBits: 0; cAccumBlueBits: 0; cAccumAlphaBits: 0; cDepthBits:16; cStencilBits:0; cAuxBuffers:0; iLayerType:PFD_MAIN_PLANE; bReserved: 0; dwLayerMask: 0; dwVisibleMask: 0; dwDamageMask: 0; ); var pixelFormat:integer; begin pixelFormat := ChoosePixelFormat(DC, @pfd); if (pixelFormat = 0) then exit; if (SetPixelFormat(DC, pixelFormat, @pfd) < TRUE) then exit; end; ``` Inicjalizacja maszyny stanu Open GL (GLInit). --------------------------------------------------------- Procedura inicjalizacyjna maszyny stanu Open GL odpowiada za ustawienie sposobu wykonywania przekształceń, parametry rzutowania. Mogą być w niej zainicjowane również funkcje ukrywania powierzchni, ukrywania ścian niewidocznych (co w przypadku dużej ilości tworzonych elementów ma za zadanie przyśpieszenie działania skompilowanego programu). Przykładowy schemat procedury inicjalizującej maszynę stanu Open GL przedstawia poniższy przykład: ```delphi procedure Tprez_form.GLInit(); begin //ustawienie sposobu wykonywania przekształceń w Open GL glMatrixMode(GL_PROJECTION); //macierz rzutowania //parametry rzutowania perspektywicznego glFrustum(-0.1, 0.1, -0.1, 0.1, 0.3, 25.0); //ponowne ustawienie sposobu wykonywania przekształceń w Open GL glMatrixMode(GL_MODELVIEW); //macierz modelowania //usunięcie ukrytych powierzchni glEnable(GL_DEPTH_TEST); //ustawienie kierunku tworzenia wierzchołków wielokątów glFrontFace(GL_CCW); //ukrywanie tylnych ścian glCullFace(GL_BACK); end; ``` GDZIE: ### Macierz modelowania Macierz modelowania glMatrixMode definiuje układ współrzędnych wykorzystywanych podczas tworzenia obiektów i związana jest z otrzymywanym rezultatem przekształceń wierzchołków. Informuje ona maszynę OpenGL, że będzie modelowana macierz modelowania (GL_MODELVIEW), macierz rzutowania (GL_PROJECTION) lub macierz tekstury (GL_TEXTURE). ### Rzutowanie perspektywistyczne Rzutowanie perspektywiczne glFrustrum pozwala uzyskać bardziej realistyczny obraz trójwymiarowego świata. W efekcie rysowania perspektywicznego obiekty znajdujące się dalej od obserwatora są rysowane na ekranie jako mniejsze. Rzutowanie perspektywistyczne polega na zastosowaniu bryły w kształcie ściętego ostrosłupa skierowanego mniejszą podstawą w stronę obserwatora. Open Gl, podczas rzutowania, przekształca ostrosłup w prostopadłościan i w efekcie obiekty znajdujące się dalej są bardziej pomniejszane od tych znajdujących się bliżej. Wielkość pomniejszenia realizuje się poprzez zmianę rozmiarów obu podstaw ostrosłupa. W przypadku gdy obie podstawy ostrosłupa są tych samych wymiarów uzyskane zostanie rzutowanie ortograficzne /zwane też równoległym/. GlFrustrum(Gldouble left, Gldouble right, Gldouble bottom, Gldouble top, Gldouble near, Gldouble far) gdzie: - left, right, bottom, top ? wyznaczają płaszczyznę obcięcia zawierającą mniejszą podstawę ostrosłupa, - near, far ? określają odległość do mniejszej i większej podstawy ostrosłupa, - wierzchołki większej podstawy wyznacza się jako punkty przecięcia linii przechodzących przez punkt obserwatora i wierzchołki mniejszej podstawy z dalszą płaszczyzną obcięcia, Im bliżej więc znajdować się będzie obserwator względem mniejszej z podstaw ostrosłupa, tym większa będzie druga podstawa oraz większe wrażenie perspektywy. ### Rzutowanie ortograficzne Rzutowanie ortograficzne wykorzystywane jest w grach opartych na grafice dwuwymiarowej, w komputerowym wspomaganiu projektowania. Rzutowanie ortograficzne nie tworzy tak realistycznego obrazu świata jak rzutowanie perspektywistyczne. ### Usuwanie ukrytych powierzchni Usunięcie ukrytych powierzchni GL_DEPTH_TEST - polecenie glEnable(GL_DEPTH_TEST) aktywuje usuwanie ukrytych powierzchni. ### Kierunek tworzenia wierzchołków Ustawienie kierunku tworzenia wierzchołków wielokątów glFrontFace ? kierunek tworzenia wierzchołków wielokątów może być określony w kierunku przeciwnym do obrotu wskazówek zegara (GL_CCW) lub zgodnym (GL_CW). ### Ukrywanie ścian Ukrywanie ścian glCullFace ? określa która ze stron ścian ma być rysowana. Może przyjmować wartości: - GL_FRONT (przednie ściany), - GL_BACK (tylne ściany), - GL_FRONT_AND_BACK (przednie i tylne ściany ? nie ma zwykle sensu). Procedura rysująca - tworzącą grafikę trójwymiarową (Draw). -------------------------------------------------------------------------- Wywołanie procedury Draw należy umieszczać zawsze w procedurach obsługujących ruch myszą oraz w procedurach obsługujących ruch do przodu, do tyłu, w bok (klawisze kursorów). Można umieścić również jej wywołanie w procedurze Timer1Timer(Sender: TObject) dla elementów ruchomych np.: obracający się krąg na danej powierzchni czy poruszający się inny przedmiot w przestrzeni X,Y,Z. W procedurze Draw() umieszczane są najczęściej poniższe funkcje: ```delphi procedure Tprez_form.Draw(); begin //zeruje bufor ekranu I bufor głębi glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT); //resetuje macierz widoku modelu glLoadIdentity(); //przesunięcie o wartość jednostek zmiennej ?przesunięcie? wzdłuż osi Z //(znak ?-? powoduje przesunięcie wstecz), dla osi X i Y wartości są 0.0 //czyli brak przesunięcia //dla obcnej sceny przesunięcie wynosi ?10.0 czyli oddalenie od miejsca obserwatora glTranslatef(0.0,0.0, przesunięcie); //obrót dookoła osi X o wartość obr_poziom, dla osi Y i Z //wprowadzona jest wartość 0 czyli brak obrotu glRotatef(obr_poziom, 1, 0, 0); //obrót dookoła osi Y o wartość obr_pion, dla osi X i Z //wprowadzona jest wartość 0 czyli brak obrotu //obroty należy wykonywać dla każdej płaszczyzny osobno glRotatef(obr_pion, 0, 1, 0); //włączenie, poinformowanie OpenGL o braku rysowania płaszczyzn //zainicjowanych funkcją glCullFace() ? brak obliczeń dla niewidocznych stron glEnable(GL_CULL_FACE); //włączenie tekstur dwuwymiarowych glEnable(GL_TEXTURE_2D); //włączenie tworzenia tekstury glTexGenf(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); glTexGenf(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); glBindTexture(GL_TEXTURE_2D, jakaś_tekstura); //koniec tworzenia tekstury //narysowanie kwadratu wypełnionego teksturą ?jakaś_tekstura? glBegin(GL_QUADS); glTexCoord2f(0.0, 0.0); glVertex3f(Vertex[i].X, Vertex[i].Y, Vertex[i].Z); glTexCoord2f(1.0, 0.0); glVertex3f(Vertex[i].X, Vertex[i].Y, Vertex[i].Z); glTexCoord2f(1.0, 1.0); glVertex3f(Vertex[i].X, Vertex[i].Y, Vertex[i].Z); glTexCoord2f(0.0, 1.0); glVertex3f(Vertex[i].X, Vertex[i].Y, Vertex[i].Z); glEnd(); //przełączenie buforów SwapBuffers(wglGetCurrentDC); end; ``` Gdzie: ### Funkcja SwapBuffers Funkcja SwapBuffers ze zmienną jako parametr przechowującą kontekst urządzenia powoduje przełączenie buforów, zapewniając płynność animacji. Rysowana animacja w procedurze Draw() umieszczana jest w niewidocznym dla obserwatora buforze i następnie po jej narysowaniu za pomocą funkcji SwapBuffers jest przedstawiana obserwatorowi. ### Funkcja glFlush Funkcja glFlush() opróżnia natomiast bufor. ### Funkcja glClear Funkcja glClear zeruje bufory kolorów i głębi i w efekcie wypełnia okno kolorem czarnym. ### Funkcja glLoadIdentify Funkcja glLoadIdentity powoduje wyczyszczenie bieżącej macierzy przekształceń w celu umożliwienia wykonania kolejnych przekształceń widoku. ### Funkcja glTranslatef Funkcja glTranslatef reprezentuje przekształcenia modelowania, podobnie jak funkcja glRotatef. Należy ją stosować w przypadku braku wykorzystania /jak w naszym przykładzie/ funkcji gluLookAt. Funkcja glTranslate wykonuje przesunięcie o daną wartość X,Y,Z ? w naszym przykładzie przesunięcie następuje wzdłuż osi Z. ### Funkcja glRotatef Funkcja glRotatef podobnie jak funkcja glTranslatef reprezentuje przekształcenia modelowania o daną wartość. Jak sama nazwa wskazuje powoduje ona obrót wokół danej osi współrzędnych. Wybranie obrotu dla osi reprezentuje wartość 1 wprowadzona w odpowiednim miejscu, na przykład: - glRotatef(obr, 1, 0, 0) ? obrót o wartość obr wokół osi X - glRotatef(obr, 0, 1, 0) ? obrót o wartość obr wokół osi Y - glRotatef(obr, 0, 0, 1) ? obrót o wartość obr wokół osi Z Obroty dla każdej osi należy wykonywać osobno. Nie wolno łączyć obrotu wokół osi X i Y w jednej funkcji. ### Funkcja glEnable Funkcja glEnable włącza różne stany OpenGl, natomiast funkcja glDisable powoduje wyłączenie stanu maszyny OpenGl. Na przykład: glEnable(GL_FOG) powoduje włączenie mgły, natomiast glDisable(GL_FOG) jej wyłączenie. ### Funkcja glBegin Funkcja tworząca grafikę glBegin() ? funkcja ta przekazuje maszynie OpenGL informację o rozpoczęciu tworzenia grafiki oraz o typie wykorzystywanych elementów. Posiada ona postać: GlBegin(Glenum mode) Typ wykorzystywanych elementów określony jest za pomocą parametru mode i przyjmować on może wartości: - GL_POINTS ? pojedyncze punkty, - GL_LINES ? odcinki, - GL_LINE_STRIP ? sekwencja połączonych odcinków, - GL_LINE_LOOP ? zamknięta sekwencja połączonych odcinków, - GL_TRIANGLES ? pojedyncze trójkąty, - GL_TRIANGLE_STRIP ? sekwencja połączonych trójkątów, - GL_TRIANGLE_FAN ? sekwencja trójkątów posiadających jeden wspólny wierzchołek, - GL_QUADS ? czworokąty, - GL_QUAD_STRIP ? sekwencja połączonych trójkątów, - GL_POLYGON ? wielokąty o dowolnej liczbie wierzchołków. Każde wywołanie funkcji glBegin(musi być zakończone wywołaniem funkcji glEnd(). ### Funkcja glEnd Funkcja glEnd() powiadamia maszynę OpenGl o zakończeniu tworzenia grafiki z wykorzystaniem elementów określonych jako parametr funkcji glBegin. Funkcja glEnd nie posiada parametrów. Należy ponadto pamiętać, iż nie wolno zagnieżdżać funkcji glBegin oraz glEnd, czyli nie wolno wywoływać ich po raz kolejny w bloku funkcji glBegin i glEnd. Wewnątrz funkcji glBegin oraz glEnd można tylko wywoływać funkcje: - glVertex, - glColor, - glIndex, - glNormal, - glTexCoord, - glEvalCoord, - glEvalPoint, - glMaterial, - glEdgeFlag, - glCallList, - glCallLists. ### Funkcja glVertex Funkcja glVertex() wywoływana jest w celu określenia punktu w przestrzeni. Poniżej przedstawiam schemat wywołania funkcji: GlVertex[2,3,4][d,f,i,s][wektor] gdzie: - cyfra to liczba wymiarów, - litera określa typ danych: double, float, int lub short, - wektor oznacza tablicę za pomocą której zostaną przekazane parametry funkcji. W kodzie można użyć: glVertex3f(Vertex[i].X, Vertex[i].Y, Vertex[i].Z). Tablica Vertex zaimplementowana musi zostać w sekcji var formy jako TCoord. Typ TCoord jest natomiast rekordem zawierającym zmienne X,Y,Z typu glFloat. Całość implementacji zmiennych tablicy i rekordu wyglądać może następująco: ```delphi type Tprez_form = class(TForm) ? procedury ? private { Private declarations } ? zmienne ? procedury public { Public declarations } end; type //rekord TCoord = Record X, Y, Z : glFLoat; end; var prez_form: Tprez_form; //tablica Vertex : Array of TCoord; ``` W kodzie źródłowym w procedurze Draw można narysować GL_QUADS np.: w sposób jak poniżej stosując pętlę while. Parametr ?i? jest zmienną przetrzymującą liczby typu integer. ```delphi while i < 16 do begin glBegin(GL_QUADS); glTexCoord2f(0.0, 0.0); glVertex3f(Vertex[i].X, Vertex[i].Y, Vertex[i].Z); i := i + 1; glTexCoord2f(1.0, 0.0); glVertex3f(Vertex[i].X, Vertex[i].Y, Vertex[i].Z); i := i + 1; glTexCoord2f(1.0, 1.0); glVertex3f(Vertex[i].X, Vertex[i].Y, Vertex[i].Z); i := i + 1; glTexCoord2f(0.0, 1.0); glVertex3f(Vertex[i].X, Vertex[i].Y, Vertex[i].Z); i := i + 1; glEnd(); end; ``` Powyższy przykład narysuje cztery ?kwadraty? w zależności od danych przetrzymywanych w tablicy Vertex. Inny przykład użycia funkcji glVertex: ```delphi glBegin(GL_POINTS) glVertex(0.0, 0.0, 0.0); glEnd(); ``` Pierwszy wiersz powyższego przykładu informuje maszynę OpenGL, iż będą rysowane punkty. Kolejny wiersz rysuje punkty a ostatni informuje maszynę OpenGL o zakończeniu rysowania. Można również wewnątrz bloku wywołań funkcji glBegin() oraz glEnd wywołać funkcję glVertex() dowolną liczbę razy co przyśpiesza działanie programu, np.: ```delphi glBegin(GL_POINTS) glVertex(0.0, 0.0, 0.0); glVertex(0.0, 1.0, 0.0); glEnd(;) ``` Poinformowanie maszyny OpenGL o rysowaniu odcinków oznacza natomiast, iż punkty mają być interpretowane jako końce odcinków. Pokazuje to poniższy przykład: ```delphi glBegin(GL_LINES) glVertex(-1.0, -1.0, 0.0); glVertex(2.0, 1.0, 0.0); glEnd(); ``` Wewnątrz bloku wywołań funkcji glBegin oraz glEnd można rysować wiele odcinków. Każde kolejne dwa punkty traktowane będą jako końce nowego odcinka. ### Funkcja glTexCoord2f Funkcja glTexCoord2f() określa współrzędne tekstury. Tworzenie sceny wymaga określenia współrzędnych tekstury dla wszystkich wierzchołków. Współrzędne tekstury pozwalają ustalić położenie tekseli na rysowanym objekcie. Współrzędne (0, 0) oznaczają lewy dolny narożnik tekstury. Współrzędne (1, 1) prawy górny narożnik. Podczas rysowania wielokąta trzeba określić współrzędne tekstury dla każdego z jego wierzchołków. W przypadku tekstur dwuwymiarowych mają one postać (s, t), gdzie s i t przyjmują wartości z przedziału od 0 do 1.
          (0.0, 1.0)                           (1.0, 1.0)
              |------------------------------------|
              |                                    |
              |                                    |
              |                                    |
              |                                    |
              |                                    |
              |                                    |
              |                                    |
              |------------------------------------|
          (0.0, 0.0)                           (1.0, 0.0)
Włączenie tworzenia tekstur: Funkcja glTesGenf stosowana jest przy odwzorowaniu otoczenia /np.: w zastosowaniu czcionki konturowej pokrytej teksturą/. Pierwszy parametr informuje maszynę OpenGl o tym, która ze współrzędnych tekstur będzie generowana automatycznie /może on przyjmować wartość GL_S lub GL_T w odniesieniu do tekstur dwuwymiarowych/.Drugi parametr określa tryb odwzorowania tekstury używany podczas automatycznej generacji współrzędnej i może przyjmować wartości: GL_EYE_LINEAR ? tekstura umieszczana jest w stałym miejscu ekranu, obiekty pokryte są teksturą, GL_OBJECT_LINEAR ? tekstura umieszczana jest na obiekcie, GL_SPHERE_MAP ? tekstura reprezentuje odwzorowanie otoczenia (mapę sferyczną). ### Funkcja glTexParamateri Funkcja glTexParameteri ? okresla sposób filtrowania tekstury. A oto jej struktura: GlTexParameteri(Glenum target, Glenum pname, Glint param) gdzie: * target reprezentuje rodzaj używanych tekstur, może przyjmować wartości: GL_TEXTURE_1D, GL_TEXTURE_2D lub GL_TEXTURE3D, * pname pozwala określić, czy definiuje się obsługę powiększania czy pomniejszania i może przyjmować odpowiednio GL_TEXTURE_MAG_FILTER lub GL_TEXTURE_MIN_FILTER, * param może przyjmować wartości: GL_NEAREST ? używa teksela położonego najbliżej środka rysowanego piksela, GL_LINEAR ? stosuje liniową interpolację (średnio ważoną) czterech tekseli położonych najbliżej środka rysowanego piksela, GL_NEAREST_MIPMAP_NEAREST ? używa obrazu o najbardziej zbliżonej rozdzielczości do rozdzielczości wielokąta oraz filtr GL_NEAREST, GL_NEAREST_MIPMAP_LINEAR ? używa obrazu o najbardziej zbliżonej rozdzielczości do rozdzielczości wielokąta oraz filtr GL_LINEAR, GL_LINEAR_MIPMAP_NEAREST ? stosuje liniową interpolację dwóch mipmap o najbardziej zbliżonej rozdzielczości wielokąta oraz używa filtr GL_NEAREST, GL_LINEAR_MIPMAP_LINEAR ? stosuje liniową interpolację dwóch mipmap o najbliższej zbliżonej rozdzielczości do rozdzielczości wielokąta oraz używa filtra GL_LINEAR. Filtry wykorzystujące mipmapy można stosować jedynie dla parametru GL_TEXTURE_MIN_FILTER. ### Funkcja glBindTexture Funkcja glBindTexture wiąże obiekt tekstury z bieżącą teksturą. Aby skorzystać w programie z wielu różnych tekstur należy przy zmianie tekstury za każdym razem wywoływać powyższą funkcję glBindTexture. Procedura wywoływana podczas zmiany wielkości okna (FormResize). ------------------------------------------------------------------------------------- Po zmianie wielkości okna niezbędne jest ponowne wywołanie procedur SetupPixelFormat oraz GLInit. Należy również wywołać funkcje kontekstu tworzenia grafiki oraz kontekstu urządzenia. Przykładowy schemat procedury zawarty jest poniżej: ```delphi procedure Tprez_form.FormResize(Sender: TObject); var //dla Open GL DC:HDC; RC:HGLRC; begin // dla Open GL DC:=GetDC(Handle); SetupPixelFormat(DC); RC:=wglCreateContext(DC); wglMakeCurrent(DC, RC); GLInit; end; ``` Informacje końcowe. ------------------------- Wywołanie funkcji wczytujących wszelkiego grafiki do zmiennych można wykonać w dwojaki sposób. zakładając, iż wielkość formy programu nie będzie ulegać zmianom można tekstury załadować w procedurze FormActivate po wywołaniu procedur SetupPixelFormat, GLInit oraz po wywołaniu funkcji kontekstu tworzenia grafiki, jak i kontekstu urządzenia. Przedstawia to poniższy przykład: ```delphi procedure Tprez_form.FormActivate(Sender: TObject); var DC:HDC; RC:HGLRC; begin DC:=GetDC(Handle); SetupPixelFormat(DC); RC:=wglCreateContext(DC); wglMakeCurrent(DC, RC); GLInit; //zmienna musi być zainicjowana w sekcji private jako string //zmienna := 'plik.jpg'; //jeżeli plik podstawiony do zmiennej istnieje ... if fileexists(sc_programu + 'image\' + zmienna_jpg) then begin //załadowanie tekstury do zmiennej zmienna_text zainicjowanej //w sekcji private jako glUnit LoadTexture(sc_programu + 'image\' + zmienna_jpg, zmienna_text, false); end; end; ``` przy założeniu swobodnych zmian wielkości formy należy tekstury ładować w umieszczając funkcje na końcu procedury GLInit, jak na poniższym przykładzie: ```delphi procedure Tprez_form.GLInit(); begin glMatrixMode(GL_PROJECTION); glFrustum(-0.1, 0.1, -0.1, 0.1, 0.3, 25.0); glMatrixMode(GL_MODELVIEW); glEnable(GL_DEPTH_TEST); //zmienna musi być zainicjowana w sekcji private jako string //zmienna := 'plik.jpg'; //jeżeli plik podstawiony do zmiennej istnieje ... if fileexists(sc_programu + 'image\' + zmienna_jpg) then begin //załadowanie tekstury do zmiennej zmienna_text zainicjowanej //w sekcji private jako glUnit LoadTexture(sc_programu + 'image\' + zmienna_jpg, zmienna_text, false); end; end; ``` Gotowy przykład implementacji maszyny stanu OpenGL w Delphi. ========================================= Kostka 3D ------------------------- Przykład poniżej przedstawia obracający się sześcian pokryty różnymi teksturami. Umieszczenie procedury FormResize pozwala na swobodne zmiany wielkości formy. Dwa przyciski button pozwalają zmienić interwał Timera co powoduje zmianę szybkości przeprowadzanej animacji. ![screen_kostka_opengl.jpg](//static.4programmers.net/uploads/attachment/4ccd36d6b764f.jpg) ```delphi // ------------------------------------------------------------- // Autor: rk7771 // -= wrzesień 2005 =- // Opis: // Obracający się sześcian pokryty teksturą // ------------------------------------------------------------- unit projekt_1_unit; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, Gl, Glu, OpenGL, textures, ExtCtrls, Buttons, StdCtrls; type Tprojekt_1_form = class(TForm) Timer1: TTimer; Button1: TButton; Button2: TButton; procedure FormResize(Sender: TObject); procedure Button2Click(Sender: TObject); procedure Button1Click(Sender: TObject); procedure FormCreate(Sender: TObject); procedure FormActivate(Sender: TObject); procedure FormPaint(Sender: TObject); procedure GLInit(); procedure setupPixelFormat(DC:HDC); procedure Timer1Timer(Sender: TObject); private { Private declarations } wielk : double; obrot_poziom : integer; obrot_pion : integer; sc_programu : string; jpg1 : string; jpg2 : string; jpg3 : string; jpg4 : string; jpg5 : string; jpg6 : string; FrontTex : glUint; BackTex : glUint; TopTex : glUint; BottomTex : glUint; LeftTex : glUint; RightTex : glUint; procedure Draw(); public { Public declarations } end; var projekt_1_form: Tprojekt_1_form; implementation {$R *.dfm} procedure Tprojekt_1_form.FormActivate(Sender: TObject); var //dla Open GL DC:HDC; RC:HGLRC; begin projekt_1_form.Top := 25; projekt_1_form.Left := 25; sc_programu:=ExtractFilePath(ParamStr(0)); Canvas.Font.Color := clRed; Canvas.Font.Size := 12; Canvas.TextOut(30, 130, 'Ładowanie grafiki, proszę czekać ...'); Application.ProcessMessages; jpg1 := '1.jpg'; jpg2 := '2.jpg'; jpg3 := '3.jpg'; jpg4 := '4.jpg'; jpg5 := '5.jpg'; jpg6 := '6.jpg'; // dla Open GL DC:=GetDC(Handle); SetupPixelFormat(DC); RC:=wglCreateContext(DC); wglMakeCurrent(DC, RC); GLInit; wielk := -6.0; end; procedure Tprojekt_1_form.FormPaint(Sender: TObject); begin Draw(); end; procedure Tprojekt_1_form.GLInit(); begin glMatrixMode(GL_PROJECTION); glFrustum(-0.1, 0.1, -0.1, 0.1, 0.3, 25.0); glMatrixMode(GL_MODELVIEW); glEnable(GL_DEPTH_TEST); //kontrola isnienia plików jpg if fileexists(sc_programu + 'image\' + jpg1) and fileexists(sc_programu + 'image\' + jpg2) and fileexists(sc_programu + 'image\' + jpg3) and fileexists(sc_programu + 'image\' + jpg4) and fileexists(sc_programu + 'image\' + jpg5) and fileexists(sc_programu + 'image\' + jpg6) then begin //wczytanie plików jpg do zmiennych LoadTexture(sc_programu + 'image\' + jpg1, FrontTex, false); LoadTexture(sc_programu + 'image\' + jpg2, BackTex, false); LoadTexture(sc_programu + 'image\' + jpg3, TopTex, false); LoadTexture(sc_programu + 'image\' + jpg4, BottomTex, false); LoadTexture(sc_programu + 'image\' + jpg5, LeftTex, false); LoadTexture(sc_programu + 'image\' + jpg6, RightTex, false); end; end; procedure Tprojekt_1_form.setupPixelFormat(DC:HDC); const pfd:TPIXELFORMATDESCRIPTOR = ( nSize:sizeof(TPIXELFORMATDESCRIPTOR); nVersion:1; dwFlags:PFD_SUPPORT_OPENGL or PFD_DRAW_TO_WINDOW or PFD_DOUBLEBUFFER; iPixelType:PFD_TYPE_RGBA; cColorBits:24; cRedBits:0; cRedShift:0; cGreenBits:0; cGreenShift:0; cBlueBits:0; cBlueShift:0; cAlphaBits:0; cAlphaShift:0; cAccumBits: 0; cAccumRedBits: 0; cAccumGreenBits: 0; cAccumBlueBits: 0; cAccumAlphaBits: 0; cDepthBits:16; cStencilBits:0; cAuxBuffers:0; iLayerType:PFD_MAIN_PLANE; bReserved: 0; dwLayerMask: 0; dwVisibleMask: 0; dwDamageMask: 0; ); var pixelFormat:integer; begin pixelFormat := ChoosePixelFormat(DC, @pfd); if (pixelFormat = 0) then exit; if (SetPixelFormat(DC, pixelFormat, @pfd) < TRUE) then exit; end; procedure Tprojekt_1_form.Draw(); begin sc_programu:=ExtractFilePath(ParamStr(0)); //jpg - kontrola istnienia plików if fileexists(sc_programu + 'image\' + jpg1) and fileexists(sc_programu + 'image\' + jpg2) and fileexists(sc_programu + 'image\' + jpg3) and fileexists(sc_programu + 'image\' + jpg4) and fileexists(sc_programu + 'image\' + jpg5) and fileexists(sc_programu + 'image\' + jpg6) then begin Application.ProcessMessages; glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT); glLoadIdentity(); glTranslatef(0.0,0.0, wielk); glRotatef(obrot_poziom, 1, 0, 0); glRotatef(obrot_pion, 0, 1, 0); glEnable(GL_CULL_FACE); glEnable(GL_TEXTURE_2D); glTexGenf(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); glTexGenf(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); glBindTexture(GL_TEXTURE_2D, FrontTex); glBegin(GL_QUADS); // Front Face glTexCoord2f(0.0, 0.0); glVertex3f(-1.0, -1.0, 1.0); glTexCoord2f(1.0, 0.0); glVertex3f( 1.0, -1.0, 1.0); glTexCoord2f(1.0, 1.0); glVertex3f( 1.0, 1.0, 1.0); glTexCoord2f(0.0, 1.0); glVertex3f(-1.0, 1.0, 1.0); glEnd(); glBindTexture(GL_TEXTURE_2D, BackTex); glBegin(GL_QUADS); // Back Face glTexCoord2f(1.0, 0.0); glVertex3f(-1.0, -1.0, -1.0); glTexCoord2f(1.0, 1.0); glVertex3f(-1.0, 1.0, -1.0); glTexCoord2f(0.0, 1.0); glVertex3f( 1.0, 1.0, -1.0); glTexCoord2f(0.0, 0.0); glVertex3f( 1.0, -1.0, -1.0); glEnd(); glBindTexture(GL_TEXTURE_2D, TopTex); glBegin(GL_QUADS); // Top Face glTexCoord2f(0.0, 1.0); glVertex3f(-1.0, 1.0, -1.0); glTexCoord2f(0.0, 0.0); glVertex3f(-1.0, 1.0, 1.0); glTexCoord2f(1.0, 0.0); glVertex3f( 1.0, 1.0, 1.0); glTexCoord2f(1.0, 1.0); glVertex3f( 1.0, 1.0, -1.0); glEnd(); glBindTexture(GL_TEXTURE_2D, BottomTex); glBegin(GL_QUADS); // Bottom Face glTexCoord2f(1.0, 1.0); glVertex3f(-1.0, -1.0, -1.0); glTexCoord2f(0.0, 1.0); glVertex3f( 1.0, -1.0, -1.0); glTexCoord2f(0.0, 0.0); glVertex3f( 1.0, -1.0, 1.0); glTexCoord2f(1.0, 0.0); glVertex3f(-1.0, -1.0, 1.0); glEnd(); glBindTexture(GL_TEXTURE_2D, RightTex); glBegin(GL_QUADS); // Right face glTexCoord2f(1.0, 0.0); glVertex3f( 1.0, -1.0, -1.0); glTexCoord2f(1.0, 1.0); glVertex3f( 1.0, 1.0, -1.0); glTexCoord2f(0.0, 1.0); glVertex3f( 1.0, 1.0, 1.0); glTexCoord2f(0.0, 0.0); glVertex3f( 1.0, -1.0, 1.0); glEnd(); glBindTexture(GL_TEXTURE_2D, LeftTex); glBegin(GL_QUADS); // Left Face glTexCoord2f(0.0, 0.0); glVertex3f(-1.0, -1.0, -1.0); glTexCoord2f(1.0, 0.0); glVertex3f(-1.0, -1.0, 1.0); glTexCoord2f(1.0, 1.0); glVertex3f(-1.0, 1.0, 1.0); glTexCoord2f(0.0, 1.0); glVertex3f(-1.0, 1.0, -1.0); glEnd(); SwapBuffers(wglGetCurrentDC); Canvas.Brush.Style := bsClear; // ustaw tło na przeźroczyste Canvas.Font.Color := clRed; Canvas.Font.Size := 12; Canvas.TextOut(10, 30, 'Intervał timera: ' + inttostr(Timer1.Interval)); end; end; procedure Tprojekt_1_form.Timer1Timer(Sender: TObject); begin obrot_poziom := obrot_poziom + 3; obrot_pion := obrot_pion + 6; Draw(); end; procedure Tprojekt_1_form.FormCreate(Sender: TObject); begin projekt_1_form.BorderIcons := [biSystemMenu]; Timer1.Interval := 100; end; procedure Tprojekt_1_form.Button1Click(Sender: TObject); begin //spowolnienie animacji Timer1.Interval := Timer1.Interval + 5; end; procedure Tprojekt_1_form.Button2Click(Sender: TObject); begin //przyśpieszenie animacji Timer1.Interval := Timer1.Interval - 5; end; procedure Tprojekt_1_form.FormResize(Sender: TObject); var //dla Open GL DC:HDC; RC:HGLRC; begin // dla Open GL DC:=GetDC(Handle); SetupPixelFormat(DC); RC:=wglCreateContext(DC); wglMakeCurrent(DC, RC); GLInit; end; end. ```
Zegar GL ------------------------- ```delphi // ------------------------------------------------------------- // Autor: rk7771 // -= marzec 2007 =- // ZEGAR GL // ------------------------------------------------------------- unit zegar_gl_unit; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, Gl, Glu, OpenGL, ExtCtrls, textures; type TForm1 = class(TForm) Timer1: TTimer; procedure Timer1Timer(Sender: TObject); procedure FormPaint(Sender: TObject); procedure FormDestroy(Sender: TObject); procedure FormCreate(Sender: TObject); procedure kolor_tarczy(); private { Private declarations } //dla Open GL DC:HDC; RC:HGLRC; //tarcza zegara tarcza_jpg : string; tarcza_text : glUint; //kolory tarczy zegara R_color, G_color, B_color : glFLoat; //parametr dla zmiany koloru x_color : integer; procedure GLInit(); procedure setupPixelFormat(DC:HDC); public { Public declarations } sc_programu : string; procedure draw(); end; var Form1: TForm1; implementation {$R *.dfm} procedure TForm1.FormCreate(Sender: TObject); begin sc_programu:=ExtractFilePath(ParamStr(0)); form1.BorderIcons := [biSystemMenu]; form1.BorderStyle := bsSingle; R_color := 1.0; G_color := 1.0; B_color := 1.0; x_color := 0; DC:=GetDC(Handle); SetupPixelFormat(DC); RC:=wglCreateContext(DC); wglMakeCurrent(DC, RC); glLoadIdentity; GLInit; //wczytanie obrazków //TARCZA tarcza_jpg := 'tarcza.jpg'; if fileexists(sc_programu + tarcza_jpg) then begin LoadTexture(sc_programu + tarcza_jpg, tarcza_text, false); end; end; procedure TForm1.FormDestroy(Sender: TObject); begin wglmakecurrent(0,0); wgldeletecontext(DC); releasedc(handle,DC); end; procedure TForm1.GLInit(); begin // set viewing projection glMatrixMode(GL_PROJECTION); glFrustum(-0.1, 0.1, -0.1, 0.1, 0.3, 25.0); // position viewer glMatrixMode(GL_MODELVIEW); glEnable(GL_DEPTH_TEST); //kierunek przeciwny do kierunku //ruchu wskazówek zegara przy tworzeniu //wierzchołków wielokątów glFrontFace(GL_CCW); //ukrywanie tylnych ścian glCullFace(GL_BACK); end; procedure TForm1.setupPixelFormat(DC:HDC); const pfd:TPIXELFORMATDESCRIPTOR = ( nSize:sizeof(TPIXELFORMATDESCRIPTOR); nVersion:1; dwFlags:PFD_SUPPORT_OPENGL or PFD_DRAW_TO_WINDOW or PFD_DOUBLEBUFFER; iPixelType:PFD_TYPE_RGBA; cColorBits:24; cRedBits:0; cRedShift:0; cGreenBits:0; cGreenShift:0; cBlueBits:0; cBlueShift:0; cAlphaBits:0; cAlphaShift:0; cAccumBits: 0; cAccumRedBits: 0; cAccumGreenBits: 0; cAccumBlueBits: 0; cAccumAlphaBits: 0; cDepthBits:16; cStencilBits:0; cAuxBuffers:0; iLayerType:PFD_MAIN_PLANE; bReserved: 0; dwLayerMask: 0; dwVisibleMask: 0; dwDamageMask: 0; ); var pixelFormat:integer; begin pixelFormat := ChoosePixelFormat(DC, @pfd); if (pixelFormat = 0) then exit; if (SetPixelFormat(DC, pixelFormat, @pfd) < TRUE) then exit; end; procedure TForm1.FormPaint(Sender: TObject); begin draw(); end; procedure TForm1.draw(); var SysTime : SystemTime; begin if getasynckeystate(VK_ESCAPE) < 0 then begin close; end; if getasynckeystate(VK_F2) < 0 then begin kolor_tarczy(); end; GetLocalTime(SysTime); glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT); glLoadIdentity(); glEnable(GL_TEXTURE_2D); glTexGenf(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); glTexGenf(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); glPushMatrix(); glTranslatef(0, 0, -3.0); glColor3f(R_color, G_color, B_color); glBindTexture(GL_TEXTURE_2D, tarcza_text); glBegin(GL_QUADS); glTexCoord2f(0.0, 1.0); glVertex3f(-1, 1, 0); glTexCoord2f(0.0, 0.0); glVertex3f(-1, -1, 0); glTexCoord2f(1.0, 0.0); glVertex3f(1, -1, 0); glTexCoord2f(1.0, 1.0); glVertex3f(1, 1, 0); glEnd(); glNormal3f( 0.0, 0.0, 1.0); // hours glPushMatrix(); glRotate(-SysTime.wHour*30 - SysTime.wMinute/2 +90 , 0, 0, 1); glBegin(GL_QUADS); glColor3f(0.4, 0.4, 0.4); glVertex3f(-0.2, 0, 0); glVertex3f(0, -0.03, 0); glVertex3f(0.6, 0, 0); glVertex3f(0, 0, 0.1); glColor3f(1, 0.2, 0.2); glVertex3f(-0.2, 0, 0); glVertex3f(0, 0, 0.1); glVertex3f(0.6, 0, 0); glVertex3f(0, 0.03, 0); glEnd(); glPopMatrix(); // minutes glPushMatrix(); glRotate(-SysTime.wMinute*6 - SysTime.wSecond/10 +90, 0, 0, 1); glBegin(GL_QUADS); glColor3f(0.4, 0.4, 0.4); glVertex3f(-0.2, 0, 0.1); glVertex3f(0, -0.03, 0.1); glVertex3f(0.7, 0, 0.1); glVertex3f(0, 0, 0.2); glColor3f(0.8, 0.6, 0.2); glVertex3f(-0.2, 0, 0.1); glVertex3f(0, 0, 0.1); glVertex3f(0.7, 0, 0.1); glVertex3f(0, 0.03, 0.1); glEnd(); glPopMatrix(); // seconds glPushMatrix(); glRotate(-SysTime.wSecond*6 +90, 0, 0, 1); glBegin(GL_QUADS); glColor3f(0.4, 0.4, 0.4); glVertex3f(-0.15, 0, 0.1); glVertex3f(0, 0, 0.1); glVertex3f(0.8, 0, 0.1); glVertex3f(0, 0.025, 0.1); glEnd(); glPopMatrix(); // seconds glPushMatrix(); glTranslate(0, -0.55, 0); glRotate(-SysTime.wSecond*6+90, 0, 0, 1); glBegin(GL_QUADS); glColor3f(0.2, 0.2, 0.2); glVertex3f(-0.08, 0, 0.1); glVertex3f(0, 0, 0.1); glVertex3f(0.25, 0, 0.1); glVertex3f(0, 0.01, 0.1); glEnd(); glPopMatrix(); glPopMatrix(); SwapBuffers(wglGetCurrentDC); Canvas.Font.Size := 12; //przezroczysty kolor tła Canvas.Brush.Style := bsClear; //granatowe napisy Canvas.Font.Color := clNavy; Canvas.TextOut(65, 50, FormatDateTime('h:nn:ss', Time)); //zielone napisy Canvas.Font.Color := clGreen; Canvas.TextOut(66, 51, FormatDateTime('h:nn:ss', Time)); end; procedure TForm1.Timer1Timer(Sender: TObject); begin draw(); end; procedure TForm1.kolor_tarczy(); begin inc(x_color); if x_color > 17 then x_color := 0; if x_color = 0 then begin //biały R_color := 1.0; G_color := 1.0; B_color := 1.0; end; if x_color = 1 then begin //jasny szary R_color := 0.7; G_color := 0.7; B_color := 0.7; end; if x_color = 2 then begin //szary R_color := 0.5; G_color := 0.5; B_color := 0.5; end; if x_color = 3 then begin //ciemny szary R_color := 0.3; G_color := 0.3; B_color := 0.3; end; if x_color = 4 then begin //czarny R_color := 0.0; G_color := 0.0; B_color := 0.0; end; if x_color = 5 then begin //jasny żółty R_color := 1.0; G_color := 1.0; B_color := 0.6; end; if x_color = 6 then begin //żółty R_color := 1.0; G_color := 0.8; B_color := 0.2; end; if x_color = 7 then begin //pomarańczowy R_color := 1.0; G_color := 0.6; B_color := 0.7; end; if x_color = 8 then begin //różowy R_color := 1.0; G_color := 0.6; B_color := 0.6; end; if x_color = 9 then begin //czerwony R_color := 1.0; G_color := 0.2; B_color := 0.2; end; if x_color = 10 then begin //fioletowy R_color := 1.0; G_color := 0.6; B_color := 1.0; end; if x_color = 11 then begin //ciemny fioletowy R_color := 0.6; G_color := 0.5; B_color := 1.0; end; if x_color = 12 then begin //jasny zielony R_color := 0.6; G_color := 1.0; B_color := 0.7; end; if x_color = 13 then begin //soczysty zielony R_color := 0.3; G_color := 1.0; B_color := 0.4; end; if x_color = 14 then begin //ciemniejszy zielony R_color := 0.3; G_color := 1.0; B_color := 0.7; end; if x_color = 15 then begin //ciemny zielony R_color := 0.0; G_color := 0.5; B_color := 0.1; end; if x_color = 16 then begin //niebieski R_color := 0.0; G_color := 0.0; B_color := 1.0; end; if x_color = 17 then begin //jasny niebieski R_color := 0.0; G_color := 1.0; B_color := 1.0; end; end; end. ``` Kod źródłowy kostki 3D: [Kostka_3D_OpenGL.zip](//4programmers.net/Download/1794/1185)

10 komentarzy

Poproszę o poprawienie formatowania bo się kompletnie rozjechało :(
Jeszcze kilka dni temu było OK.
Dzięki

Chyba coś jest nie w porządku w funkcji FormResize - u mnie jak zmieniam wielkość okna rośnie w nieskończoność ilość pamięci zajmowanej przez program! W końcu prowadzi to do błędu i zmulenia systemu. Myślę że jest to wina uruchamiania ciągle od nowa funkcji wglCreateContext. Pewnie trzeba najpierw zrobić DelateContext. Ja zrobiłem resize inaczej - poprzez dodanie na początku GLInit wywołani glViewport(0, 0, panel1.width, panel1.height); (u mnie okno OpenGL jest w panelu), natomiast w funkcji FormResize po prostu wywołuję GLInit.
Poza tym artykuł bardzo fajny :)

super art !!!!!!!!!!!!!!!!!
Już dawno takiego nie było
Tak trzymać
Pozdrawiam serdecznie

B. fajne
Czy mogę prosić o następujące:
grafika 2d - Opengl
użycie Cg

Adam Majewski

Wow niezly art ;> Nice nice ;> gw ;>

"GL_POLYGON ? wielokąty o dowolnej liczbie wierzchołków."
dodał bym tam słowo "wypukłe" za "wielokąty" ;>

Proponuje jakoś podzielić tren art na strony, bo ładowanie go jest już meczące

Poprawiłem: procedure Tprez_form.Draw(); na Tprez_form.FormPaint();

  • pewnie błąd powstał przy kopiowaniu kodu źródłowego.
    Poprawiłem: var przypisać begin na var pixelFormat:integer;
    Wyszukałem i poprawiłem literówki (mam nadzieję, że wszystkie ...)
  procedure Tprez_form.Draw();
  begin
    Draw();
  end;

Nie żebym się czepiał, ale nie powinno być tam Tprez_form.FormPaint(); ??

" );
var przypisać
begin"

E... Że co?

No i jeszcze jakieś literówki/orty się czasami zdarzają. Mimo wszystko artykuł imponujący.

OpenGL
Proponuję wrzucić ten schemat w < code >< plain >< /plain >< /code >, tylko potem kolorowanie składni się wykłada :/

Przydał by się przykład w pliku.