Janusz Ganczarski OpenGL Definiowanie sceny 3D
Spis treści Spis treści..................................... 1 1. Definiowanie sceny 3D........................... 1 1.1. Obszar renderingu............................ 1 1.1.1. Plik kwadrat2.cpp........................ 2 1.2. Rzutowanie prostokątne......................... 4 1.2.1. Plik szescian1.cpp........................ 7 1.3. Rzutowanie perspektywiczne...................... 10 1.3.1. Plik szescian2.cpp........................ 12 1.3.2. Plik szescian3.cpp........................ 16 1.4. Położenie obserwatora.......................... 19 1.4.1. Plik szescian4.cpp........................ 21 Literatura..................................... 25
1. Definiowanie sceny 3D W kolejnych programach korzystających z biblioteki OpenGL zajmiemy się podstawowymi zagadnieniami, związanymi ze sceną 3D: obszarem renderingu, rzutowaniem i położeniem obserwatora. Informacje tu zawarte stanowią podstawę do wszystkich następnych programów. 1.1. Obszar renderingu W pierwszym programie obszar renderingu, który zajmował początkowo całe okno, nie był modyfikowany podczas zmiany rozmiarów tego okna. W efekcie jedyny element sceny 3D - kwadrat - zawsze znajdował się w tym samym miejscu względem lewego dolnego narożnika okna. W aplikacjach pracujących w systemach okienkowych problem zmiany rozmiaru okna jest jednak tak powszechny, że wymaga specjalnego potraktowania. Jednym z możliwych sposobów jego rozwiązania jest dynamiczna modyfikacja modyfikacja obszaru renderingu. Służy to tego funkcja: void glviewport (GLint x, GLint y, GLsizei width, GLsizei height) której parametry oznaczają: x, y - współrzędne lewego dolnego narożnika obszaru renderingu względem lewego dolnego narożnika okna, width - szerokość okna renderingu, height - wysokość okna renderingu. Domyślnie obszar renderingu zajmuje całe okno udostępnione dla aplikacji OpenGL. W naszym drugim programie w trakcie zmiany rozmiaru okna (funkcja Reshape) będziemy modyfikować obszar renderingu na dwa sposoby. Pierwszy polega na objęciu obszarem renderingu całego dostępnego okna, drugi na takim wyborze okna renderingu aby okno zachowało pierwotny aspekt obrazu, czyli stosunek szerokości do wysokości. Oczywiście przy zastosowaniu pierwszej metody kwadrat będzie zazwyczaj zdeformowany (patrz rysunki 1 i 2). Zmiany sposobu definiowania okna renderingu można dokonać w dowolnym momencie, poprzez wybranie odpowiedniej opcji w menu podręcznym. W funkcji Menu została użyta do tej pory nieopisana funkcja z biblioteki GLUT: int glutget (GLenum type) O tym jakiego rodzaju informacje zwróci funkcja glutget decyduje parametr type. W przykładowym programie są to szerokość i wysokość okna, co odpowiada parametrom opisanym stałymi GLUT WINDOW WIDTH i GLUT WINDOW HEIGHT.
1. Definiowanie sceny 3D 2 Warto jeszcze kilka słów poświęcić zagadnieniu aspektu obrazu. Typowe monitory komputerowe posiadają aspekt 4:3, który jest zgodny z większością popularnych rozdzielczości roboczych (np. 640 480, 800 600, 1.024 768, 1.600 1.200), ale inna popularna rozdzielczość 1.280 1.024 pikseli odpowiada aspektowi 5:4. Rysunek 1. Programu Kwadrat 2 - rendering na całym oknie Rysunek 2. Programu Kwadrat 2 - rendering z zachowaniem aspektu 1:1 1.1.1. Plik kwadrat2.cpp / ( c ) Janusz G a n c z a r s k i h t t p : / /www. j a n u s z g. hg. p l JanuszG@enter. n e t. p l / #include <GL/ glut. h> #include < s t d l i b. h> // s t a ł e do o b s ł u g i menu p o d r ę c z n e g o enum FULL WINDOW, // o b s z a r r e n d e r i n g u c a ł e okno ASPECT 1 1, // o b s z a r r e n d e r i n g u a s p e k t 1 : 1
1. Definiowanie sceny 3D 3 EXIT // w y j ś c i e ; // a s p e k t o b r a z u int Aspect = FULL WINDOW; // f u n k c j a g e n e r u j ą c a s c e n ę 3D void D i s p l a y ( ) // k o l o r t ł a z a w a r t o ś ć b u f o r a k o l o r u g l C l e a r C o l o r ( 1. 0, 1. 0, 1. 0, 1. 0 ) ; // c z y s z c z e n i e b u f o r a k o l o r u g l C l e a r ( GL COLOR BUFFER BIT ) ; // k o l o r k w a d r a t u g l C o l o r 3 f ( 1. 0, 0. 0, 0. 0 ) ; // p o c z ą t e k d e f i n i c j i w i e l o k ą t a g l B e g i n (GL POLYGON) ; // k o l e j n e w i e r z c h o ł k i w i e l o k ą t a g l V e r t e x 3 f ( 0. 0, 0. 0, 0. 0 ) ; g l V e r t e x 3 f ( 0. 0, 1. 0, 0. 0 ) ; g l V e r t e x 3 f ( 1. 0, 1. 0, 0. 0 ) ; g l V e r t e x 3 f ( 1. 0, 0. 0, 0. 0 ) ; // k o n i e c d e f i n i c j i prymitywu glend ( ) ; // s k i e r o w a n i e p o l e c e ń do wykonania g l F l u s h ( ) ; // zamiana b u f o r ó w k o l o r u glutswapbuffers ( ) ; // zmiana w i e l k o ś c i okna void Reshape ( int width, int h e i g h t ) // o b s z a r r e n d e r i n g u a s p e k t 1 : 1 i f ( Aspect == ASPECT 1 1 ) // s z e r o k o ś ć okna w i ę k s z a od w y s o k o ś c i okna i f ( width > h e i g h t ) g l V i e w p o r t ( ( width h e i g h t ) / 2, 0, h e i g h t, h e i g h t ) ; e l s e // w y s o k o ś ć okna w i ę k s z a od w y s o k o ś c i okna i f ( width < h e i g h t ) g l V i e w p o r t ( 0, ( h e i g h t width ) / 2, width, width ) ; e l s e // o b s z a r r e n d e r i n g u c a ł e okno ( t a k ż e, gdy a s p e k t w y n o s i 1 : 1 ) g l V i e w p o r t ( 0, 0, width, h e i g h t ) ; // g e n e r o w a n i e s c e n y 3D D i s p l a y ( ) ; // ob sług a menu podręcznego void Menu ( int v a l u e ) switch ( v a l u e ) // o b s z a r r e n d e r i n g u c a ł e okno case FULL WINDOW: Aspect = FULL WINDOW; Reshape ( glutget (GLUT WINDOW WIDTH), glutget (GLUT WINDOW HEIGHT ) ) ; break ; // o b s z a r r e n d e r i n g u a s p e k t 1 : 1 case ASPECT 1 1 : Aspect = ASPECT 1 1 ; Reshape ( glutget (GLUT WINDOW WIDTH), glutget (GLUT WINDOW HEIGHT ) ) ;
1. Definiowanie sceny 3D 4 break ; // w y j ś c i e case EXIT : e x i t ( 0 ) ; int main ( int argc, char argv [ ] ) // i n i c j a l i z a c j a b i b l i o t e k i GLUT g l u t I n i t (& argc, argv ) ; // i n i c j a l i z a c j a b u f o r a ramki g l u t I n i t D i s p l a y M o d e (GLUT DOUBLE GLUT RGB ) ; // r o z m i a r y g ł ó w n e g o okna programu g l u t I n i t W i n d o w S i z e ( 4 0 0, 4 0 0 ) ; // u t w o r z e n i e g ł ó w n e g o okna programu glutcreatewindow ( Kwadrat 2 ) ; // d o ł ą c z e n i e f u n k c j i g e n e r u j ą c e j s c e n ę 3D glutdisplayfunc ( Display ) ; // d o ł ą c z e n i e f u n k c j i wywoływanej p r z y z m i a n i e r o z m i a r u okna glutreshapefunc ( Reshape ) ; // u t w o r z e n i e menu p o d r ę c z n e g o glutcreatemenu ( Menu ) ; // d o d a n i e p o z y c j i do menu p o d r ę c z n e g o glutaddmenuentry ( Obszar renderingu całe okno,full WINDOW) ; glutaddmenuentry ( Obszar renderingu aspekt 1 : 1, ASPECT 1 1 ) ; glutaddmenuentry ( Wyjście,EXIT ) ; // o k r e ś l e n i e p r z y c i s k u m y s z k i o b s ł u g u j ą c e j menu p o d r ę c z n e glutattachmenu (GLUT RIGHT BUTTON ) ; // w p r o w a d z e n i e programu do o b s ł u g i p ę t l i komunikatów glutmainloop ( ) ; return 0 ; 1.2. Rzutowanie prostokątne Rzutowaniem określamy odwzorowanie zawartości trójwymiarowej sceny graficznej na płaskim ekranie monitora. Biblioteka OpenGL oferuje standardowo dwie metody rzutowania: rzutowanie prostokątne i rzutowanie perspektywiczne. Domyślnie stosowane jest rzutowanie prostokątne. W rzutowaniu prostokątnym (lub ortogonalnym) proste rzutowania są prostopadłe do rzutni, która jest reprezentowana przez obszar renderingu. Z rzutowaniem prostokątnym ściśle związane jest pojęcie bryły odcinania - prostopadłościanu, który stanowi ograniczenie sceny 3D. Obiekty znajdujące się poza bryłą odcinania nie sa rysowane, a obiekty ją przecinające rysowane są tylko częściowo. Rozmiar bryły odcinania w rzutowaniu prostokątnym określa funkcja: void glortho (GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble near, GLdouble far)
1. Definiowanie sceny 3D 5 której parametry określają współrzędne punktów przecięcia płaszczyzn tworzących bryłę odcinania z osiami układu współrzędnych kartezjańskich. Płaszczyzny te opisane są następującymi równaniami: x = right x = left y = top y = bottm z = near z = far Obszar renderingu zawiera się w płaszczyźnie o równaniu z = near. Położenie poszczególnych płaszczyzn tworzących bryłę odcinania przedstawia rysunek 3. Trzeba jednak wyraźnie zwrócić uwagę, że początek układu współrzędnych nie musi znajdować się wewnątrz bryły odcinania - rozmiary i położenie bryły ograniczone są jedynie zakresem stosowanych liczb. Y top -far left right X -near Z bottom Rysunek 3. Położenie płaszczyzn bryły odcinania w rzutowaniu prostokątnym Domyślnie bryła odcinania ma postać sześcianu o bokach równych 2, którego środek pokrywa się z początkiem układu współrzędnych, co odpowiada
1. Definiowanie sceny 3D 6 wywołaniu funkcji glortho (-1,1,-1,1,-1,1). Oś OZ jest prostopadła do płaszczyzny obszaru renderingu i przechodzi przez środek tego obszaru. Dlatego rysowany w pierwszym i drugim programie kwadrat zajmował początkowo czwartą część okna. Funkcja glortho tworzy macierz rzutu prostokątnego: 2 right+left right left top+bottom top bottom far+near far near right left 0 0 2 0 top bottom 0 2 0 0 far near 0 0 0 1 która jest nastepnie mnożona przez bieżącą macierz i umieszczona na szczycie stosu z bieżącą macierzą. OpenGL zawiera kilka stosów macierzy, z których w przykładowym programie wykorzystamy stos macierzy rzutowania oraz stos macierzy modelowania. Wybór bieżącej macierzy umożliwia funkcja: void glmatrixmode (GLenum mode) gdzie parametr mode może przyjąć jedną z wartości: GL MODELVIEW - macierz modelowania, GL PROJECTION - macierz rzutowania, GL TEXTURE - macierz tekstury (omówiona później). Ponieważ początkowa wartość wybranej macierzy jest nieokreślona, przed wywołaniem glortho należy bieżącej macierzy przyporządkować macierz jednostkową. Najłatwiej można to zrobić używając funkcji: void glloadidentity (void) Analogiczne postępowanie dotyczy macierzy modelowania. Po jej wyborze przykładowym programie (plik szescian1.cpp) w funkcji Display macierzy modelowania także przyporządkowywana jest macierz jednostkowa. Jeżeli renderowana scena jest dwuwymiarowa, do ustawienia parametrów bryły odcinania w rzutowaniu prostokątnym można użyć funkcji z biblioteki GLU: void gluortho2d (GLdouble left, GLdouble right, GLdouble bottom, GLdouble top) której parametry left, right, bottom i top odpowiadają parametrom funkcji glortho, a przednia (near) i tylna (far) płaszczyzna obcinania mają wartości odpowiednio -1 i 1. W przykładowym programie początkowa bryła odcinania ma postać sześcianu o krawędziach długości 4, a rysowana figura - także sześcian - ma
1. Definiowanie sceny 3D 7 krawędzie o długości 2. Centralne umieszczenie rysowanego sześcianu w połączeniu z zastosowanym rzutowaniem prostokątnym daje w efekcie kwadrat (patrz rysunek 4). Podobnie jak w poprzednim programie możliwy jest wybór, czy scena ma być rysowana z zachowaniem początkowego aspektu obrazu czy też bez zachowania tej proporcji. Jednak w tym przypadku nie jest modyfikowany obszar renderingu ale współrzędne bryły odcinania (funkcja Reshape). Rysunek 4. Początkowe okno programu Sześcian 1 1.2.1. Plik szescian1.cpp / ( c ) Janusz G a n c z a r s k i h t t p : / /www. j a n u s z g. hg. p l JanuszG@enter. n e t. p l / #include <GL/ glut. h> #include < s t d l i b. h> // s t a ł e do o b s ł u g i menu p o d r ę c z n e g o enum FULL WINDOW, // a s p e k t o b r a z u c a ł e okno ASPECT 1 1, // a s p e k t o b r a z u 1 : 1 EXIT // w y j ś c i e ;
1. Definiowanie sceny 3D 8 // a s p e k t o b r a z u int Aspect = FULL WINDOW; // f u n k c j a g e n e r u j ą c a s c e n ę 3D void D i s p l a y ( ) // k o l o r t ł a z a w a r t o ś ć b u f o r a k o l o r u g l C l e a r C o l o r ( 1. 0, 1. 0, 1. 0, 1. 0 ) ; // c z y s z c z e n i e b u f o r a k o l o r u g l C l e a r ( GL COLOR BUFFER BIT ) ; // wybór m a c i e r z y modelowania glmatrixmode (GL MODELVIEW) ; // m a c i e r z modelowania = m a c i e r z j e d n o s t k o w a g l L o a d I d e n t i t y ( ) ; // k o l o r k r a w ę d z i s z e ś c i a n u g l C o l o r 3 f ( 0. 0, 0. 0, 0. 0 ) ; // p o c z ą t e k d e f i n i c j i k r a w ę d z i s z e ś c i a n u g l B e g i n ( GL LINES ) ; // w s p ó l r z ę d n e k o l e j n y c h k r a w ę d z i s z e ś c i a n u g l V e r t e x 3 f ( 1. 0, 1. 0, 1. 0 ) ; g l V e r t e x 3 f ( 1. 0, 1. 0, 1. 0 ) ; g l V e r t e x 3 f ( 1. 0, 1. 0, 1. 0 ) ; g l V e r t e x 3 f ( 1. 0, 1. 0, 1. 0 ) ; g l V e r t e x 3 f ( 1. 0, 1. 0, 1. 0 ) ; g l V e r t e x 3 f ( 1. 0, 1. 0, 1. 0 ) ; g l V e r t e x 3 f ( 1. 0, 1. 0, 1. 0 ) ; g l V e r t e x 3 f ( 1. 0, 1. 0, 1. 0 ) ; g l V e r t e x 3 f ( 1. 0, 1. 0, 1. 0 ) ; g l V e r t e x 3 f ( 1. 0, 1. 0, 1. 0 ) ; g l V e r t e x 3 f ( 1. 0, 1. 0, 1. 0 ) ; g l V e r t e x 3 f ( 1. 0, 1. 0, 1. 0 ) ; g l V e r t e x 3 f ( 1. 0, 1. 0, 1. 0 ) ; g l V e r t e x 3 f ( 1. 0, 1. 0, 1. 0 ) ; g l V e r t e x 3 f ( 1. 0, 1. 0, 1. 0 ) ; g l V e r t e x 3 f ( 1. 0, 1. 0, 1. 0 ) ; g l V e r t e x 3 f ( 1. 0, 1. 0, 1. 0 ) ; g l V e r t e x 3 f ( 1. 0, 1. 0, 1. 0 ) ; g l V e r t e x 3 f ( 1. 0, 1. 0, 1. 0 ) ; g l V e r t e x 3 f ( 1. 0, 1. 0, 1. 0 ) ; g l V e r t e x 3 f ( 1. 0, 1. 0, 1. 0 ) ; g l V e r t e x 3 f ( 1. 0, 1. 0, 1. 0 ) ; g l V e r t e x 3 f ( 1. 0, 1. 0, 1. 0 ) ; g l V e r t e x 3 f ( 1. 0, 1. 0, 1. 0 ) ; // k o n i e c d e f i n i c j i prymitywu glend ( ) ; // s k i e r o w a n i e p o l e c e ń do wykonania g l F l u s h ( ) ; // zamiana b u f o r ó w k o l o r u glutswapbuffers ( ) ; // zmiana w i e l k o ś c i okna void Reshape ( int width, int h e i g h t ) // o b s z a r r e n d e r i n g u c a ł e okno g l V i e w p o r t ( 0, 0, width, h e i g h t ) ;
1. Definiowanie sceny 3D 9 // wybór m a c i e r z y r z u t o w a n i a glmatrixmode ( GL PROJECTION ) ; // m a c i e r z r z u t o w a n i a = m a c i e r z j e d n o s t k o w a g l L o a d I d e n t i t y ( ) ; // p a r a m e t r y b r y ł y o b c i n a n i a i f ( Aspect == ASPECT 1 1 ) // w y s o k o ś ć okna w i ę k s z a od w y s o k o ś c i okna i f ( width < h e i g h t && width > 0) glortho ( 2. 0, 2. 0, 2. 0 h e i g h t / width, 2. 0 h e i g h t / width, 2. 0, 2. 0 ) ; e l s e // s z e r o k o ś ć okna w i ę k s z a l u b równa w y s o k o ś c i okna i f ( width >= h e i g h t && h e i g h t > 0) glortho ( 2.0 width / h e i g h t, 2. 0 width / h e i g h t, 2. 0, 2. 0, 2. 0, 2. 0 ) ; e l s e glortho ( 2. 0, 2. 0, 2. 0, 2. 0, 2. 0, 2. 0 ) ; // g e n e r o w a n i e s c e n y 3D D i s p l a y ( ) ; // ob sług a menu podręcznego void Menu ( int v a l u e ) switch ( v a l u e ) // o b s z a r r e n d e r i n g u c a ł e okno case FULL WINDOW: Aspect = FULL WINDOW; Reshape ( glutget (GLUT WINDOW WIDTH), glutget (GLUT WINDOW HEIGHT ) ) ; break ; // o b s z a r r e n d e r i n g u a s p e k t 1 : 1 case ASPECT 1 1 : Aspect = ASPECT 1 1 ; Reshape ( glutget (GLUT WINDOW WIDTH), glutget (GLUT WINDOW HEIGHT ) ) ; break ; // w y j ś c i e case EXIT : e x i t ( 0 ) ; int main ( int argc, char argv [ ] ) // i n i c j a l i z a c j a b i b l i o t e k i GLUT g l u t I n i t (& argc, argv ) ; // i n i c j a l i z a c j a b u f o r a ramki g l u t I n i t D i s p l a y M o d e (GLUT DOUBLE GLUT RGB ) ; // r o z m i a r y g ł ó w n e g o okna programu g l u t I n i t W i n d o w S i z e ( 4 0 0, 4 0 0 ) ; // u t w o r z e n i e g ł ó w n e g o okna programu glutcreatewindow ( S z e ś c i a n 1 ) ; // d o ł ą c z e n i e f u n k c j i g e n e r u j ą c e j s c e n ę 3D glutdisplayfunc ( Display ) ; // d o ł ą c z e n i e f u n k c j i wywoływanej p r z y z m i a n i e r o z m i a r u okna glutreshapefunc ( Reshape ) ; // u t w o r z e n i e menu p o d r ę c z n e g o glutcreatemenu ( Menu ) ; // d o d a n i e p o z y c j i do menu p o d r ę c z n e g o glutaddmenuentry ( Aspekt obrazu całe okno,full WINDOW) ; glutaddmenuentry ( Aspekt obrazu 1 : 1, ASPECT 1 1 ) ; glutaddmenuentry ( Wyjście,EXIT ) ; // o k r e ś l e n i e p r z y c i s k u m y s z k i o b s ł u g u j ą c e j menu p o d r ę c z n e glutattachmenu (GLUT RIGHT BUTTON ) ;
1. Definiowanie sceny 3D 10 // w p r o w a d z e n i e programu do o b s ł u g i p ę t l i komunikatów glutmainloop ( ) ; return 0 ; 1.3. Rzutowanie perspektywiczne Rzutowanie perspektywiczne daje bardziej realistyczne efekty niż rzutowanie prostokątne, stąd jest szeroko stosowane np. w grach. Parametry bryły odcinania, która przy rzutowaniu perspektywicznym ma postać ostrosłupa ściętego o wierzchołku znajdującym się w początku układu współrzędnych (patrz rysunek 5), określa funkcja: void glfrustum (GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble near, GLdouble far) Y top -far left -near right bottom X Z Rysunek 5. Położenie płaszczyzn bryły odcinania w rzutowaniu perspektywicznym
1. Definiowanie sceny 3D 11 Parametry left, right, bottom i top wyznaczają rozmiary górnej podstawy bryły odcinania (jest to obszar bezpośrednio odwzorowywany na obszar renderingu), a near i far wyznaczają położenie odpowiednio górnej i dolnej podstawy ostrosłupa (przedniej i tylnej płaszczyzny odcinania), które zawierają się w płaszczyznach o równaniach: z = near i z = far. Parametry near i far muszą mieć wartości dodatnie. Macierz rzutowania perspektywicznego, tworzona przez funkcję glfrustum i mnożona przez aktualnie wybraną macierz, ma postać: 2near right left 0 2near 0 top bottom right+left right left 0 top+bottom top bottom 0 far+near far near 2far near far near 0 0 0 0 1 0 Warto zauważyć, że precyzja działania jeszcze przez nas nieużywanego z-bufora, zależy od wartości stosunku parametrów near i far: r = far near Im większa wartość r, tym mniej efektywne jest działanie z-bufora. Oczywiście near nigdy nie może przyjąć wartości równej 0, bowiem przednia płaszczyzna odcinania przechodziła by wówczas przez środek perspektywy. Alternatywny sposób określania rzutu perspektywicznego umożliwia funkcja z biblioteki GLU: void gluperspective (GLdouble fovy, GLdouble aspect, GLdouble znear, GLdouble zfar) gdzie parametr fovy określa w stopniach kąt widzenia obserwatora zawarty w płaszczyźnie YZ ( (top, 0, bottom)), a aspect jest stosunkiem szerokości do wysokości przedniej płaszczyzny odcinania, czyli górnej podstawy ostrosłupa ograniczającego scenę 3D. Parametry znear i zfar odpowiadają parametrom near i far funkcji glfrustum. Macierz rzutowania perspektywicznego, tworzona przez funkcję gluperspective i mnożona przez aktualnie wybraną macierz, ma postać: ctg fovy 2 aspect 0 0 0 0 ctg fovy 2 0 0 2 zf ar znear znear zf ar zf ar+znear 0 0 znear zf ar 0 0 1 0
1. Definiowanie sceny 3D 12 Wewnętrznie funkcja gluperspective wykorzystuje do ustawienia macierzy rzutowania perspektywicznego funkcję glfrustum. Oto przekształcenia parametrów gluperspective na parametry glfrustum: ( ) left = aspect znear tg π fovy ( 360) right = aspect znear tg π fovy ( ) 360 bottom = znear tg π fovy ( top = znear tg π fovy 360 ) 360 W kolejnym przykładowym programie (plik szescian2.cpp) do utworzenia macierzy rzutowania perspektywicznego wykorzystamy funkcję glfrustum. Przednia płaszczyzna odcinania będzie miała takie same rozmiary jak w poprzednim programie. Zmianie ulegną natomiast współrzędne przedniej i tylnej płaszczyzny obcinania - poprzednio jedna z tych płaszczyzn miała wartość ujemną, której nie akceptuje funkcja glfrustum. Rysowanym obiektem ponownie będzie sześcian ale próba narysowania go w tym samym miejscu jak w poprzednim programie spowoduje, że będzie widoczna tylko jedna jego ściana. Wszystko dlatego, że pozostałe ściany sześcianu znajdują się poza obszarem bryły odcinania. Możliwe są trzy sposoby rozwiązania tego problemu. Pierwszy polega na zmianie współrzędnych wierzchołków sześcianu w taki sposób, aby sześcian zmieścił się w zmienionej bryle obcinania. Rozwiązanie to ma jedną zasadniczą wadę - wierzchołki sześcianu trzeba będzie modyfikować przy każdej zmianie parametrów sceny 3D. W przypadku jednego obiektu nie stanowi to specjalnego problemu, ale czyni pomysł niewykonalnym przy każdej bardziej skomplikowanej scenie 3D. Drugie, zastosowane w programie rozwiązanie, polega na przesunięciu wierzchołków sześcianu o wektor [0, 0, 3], czyli o -3 jednostki wzdłuż osi OZ. Realizuje to funkcja gltranslatef, która wywoływana jest bezpośrednio po zainicjowaniu macierzy modelowania macierzą jednostkową (patrz funkcja Display). W efekcie otrzymamy sześcian przedstawiony na rysunku 6. Należy dodać, że taka metoda jest często stosowaną praktyką. Obiekty 3D definiowane są z różnymi współrzędnymi, a następnie odpowiednio transformowane do docelowego położenia w scenie 3D. Funkcje umożliwiające takie przekształcenia poznamy bliżej w następnym odcinku kursu. Trzecią metodą jest modyfikacja położenia obserwatora sceny 3D - zapoznamy się z tą techniką jeszcze w tym odcinku. 1.3.1. Plik szescian2.cpp / ( c ) Janusz G a n c z a r s k i h t t p : / /www. j a n u s z g. hg. p l
1. Definiowanie sceny 3D 13 Rysunek 6. Początkowe okno programu Sześcian 2 JanuszG@enter. n e t. p l / #include <GL/ glut. h> #include < s t d l i b. h> // s t a ł e do o b s ł u g i menu p o d r ę c z n e g o enum FULL WINDOW, // a s p e k t o b r a z u c a ł e okno ASPECT 1 1, // a s p e k t o b r a z u 1 : 1 EXIT // w y j ś c i e ; // a s p e k t o b r a z u int Aspect = FULL WINDOW; // f u n k c j a g e n e r u j ą c a s c e n ę 3D void D i s p l a y ( ) // k o l o r t ł a z a w a r t o ś ć b u f o r a k o l o r u g l C l e a r C o l o r ( 1. 0, 1. 0, 1. 0, 1. 0 ) ; // c z y s z c z e n i e b u f o r a k o l o r u g l C l e a r ( GL COLOR BUFFER BIT ) ; // wybór m a c i e r z y modelowania glmatrixmode (GL MODELVIEW) ; // m a c i e r z modelowania = m a c i e r z j e d n o s t k o w a g l L o a d I d e n t i t y ( ) ;
1. Definiowanie sceny 3D 14 // p r z e s u n i ę c i e o b i e k t u o w e k t o r [ 0, 0, 3 ] g l T r a n s l a t e f ( 0, 0, 3. 0 ) ; // k o l o r k r a w ę d z i s z e ś c i a n u g l C o l o r 3 f ( 0. 0, 0. 0, 0. 0 ) ; // p o c z ą t e k d e f i n i c j i k r a w ę d z i s z e ś c i a n u g l B e g i n ( GL LINES ) ; // w s p ó l r z ę d n e k o l e j n y c h k r a w ę d z i s z e ś c i a n u g l V e r t e x 3 f ( 1. 0, 1. 0, 1. 0 ) ; g l V e r t e x 3 f ( 1. 0, 1. 0, 1. 0 ) ; g l V e r t e x 3 f ( 1. 0, 1. 0, 1. 0 ) ; g l V e r t e x 3 f ( 1. 0, 1. 0, 1. 0 ) ; g l V e r t e x 3 f ( 1. 0, 1. 0, 1. 0 ) ; g l V e r t e x 3 f ( 1. 0, 1. 0, 1. 0 ) ; g l V e r t e x 3 f ( 1. 0, 1. 0, 1. 0 ) ; g l V e r t e x 3 f ( 1. 0, 1. 0, 1. 0 ) ; g l V e r t e x 3 f ( 1. 0, 1. 0, 1. 0 ) ; g l V e r t e x 3 f ( 1. 0, 1. 0, 1. 0 ) ; g l V e r t e x 3 f ( 1. 0, 1. 0, 1. 0 ) ; g l V e r t e x 3 f ( 1. 0, 1. 0, 1. 0 ) ; g l V e r t e x 3 f ( 1. 0, 1. 0, 1. 0 ) ; g l V e r t e x 3 f ( 1. 0, 1. 0, 1. 0 ) ; g l V e r t e x 3 f ( 1. 0, 1. 0, 1. 0 ) ; g l V e r t e x 3 f ( 1. 0, 1. 0, 1. 0 ) ; g l V e r t e x 3 f ( 1. 0, 1. 0, 1. 0 ) ; g l V e r t e x 3 f ( 1. 0, 1. 0, 1. 0 ) ; g l V e r t e x 3 f ( 1. 0, 1. 0, 1. 0 ) ; g l V e r t e x 3 f ( 1. 0, 1. 0, 1. 0 ) ; g l V e r t e x 3 f ( 1. 0, 1. 0, 1. 0 ) ; g l V e r t e x 3 f ( 1. 0, 1. 0, 1. 0 ) ; g l V e r t e x 3 f ( 1. 0, 1. 0, 1. 0 ) ; g l V e r t e x 3 f ( 1. 0, 1. 0, 1. 0 ) ; // k o n i e c d e f i n i c j i prymitywu glend ( ) ; // s k i e r o w a n i e p o l e c e ń do wykonania g l F l u s h ( ) ; // zamiana b u f o r ó w k o l o r u glutswapbuffers ( ) ; // zmiana w i e l k o ś c i okna void Reshape ( int width, int h e i g h t ) // o b s z a r r e n d e r i n g u c a ł e okno g l V i e w p o r t ( 0, 0, width, h e i g h t ) ; // wybór m a c i e r z y r z u t o w a n i a glmatrixmode ( GL PROJECTION ) ; // m a c i e r z r z u t o w a n i a = m a c i e r z j e d n o s t k o w a g l L o a d I d e n t i t y ( ) ; // p a r a m e t r y b r y ł y o b c i n a n i a i f ( Aspect == ASPECT 1 1 ) // w y s o k o ś ć okna w i ę k s z a od w y s o k o ś c i okna i f ( width < h e i g h t && width > 0) glfrustum ( 2. 0, 2. 0, 2. 0 h e i g h t / width, 2. 0 h e i g h t / width, 1. 0, 5. 0 ) ; e l s e // s z e r o k o ś ć okna w i ę k s z a l u b równa w y s o k o ś c i okna i f ( width >= h e i g h t && h e i g h t > 0) glfrustum ( 2.0 width / h e i g h t, 2. 0 width / h e i g h t, 2. 0, 2. 0, 1. 0, 5. 0 ) ;
1. Definiowanie sceny 3D 15 e l s e glfrustum ( 2. 0, 2. 0, 2. 0, 2. 0, 1. 0, 5. 0 ) ; // g e n e r o w a n i e s c e n y 3D D i s p l a y ( ) ; // ob sług a menu podręcznego void Menu ( int v a l u e ) switch ( v a l u e ) // o b s z a r r e n d e r i n g u c a ł e okno case FULL WINDOW: Aspect = FULL WINDOW; Reshape ( glutget (GLUT WINDOW WIDTH), glutget (GLUT WINDOW HEIGHT ) ) ; break ; // o b s z a r r e n d e r i n g u a s p e k t 1 : 1 case ASPECT 1 1 : Aspect = ASPECT 1 1 ; Reshape ( glutget (GLUT WINDOW WIDTH), glutget (GLUT WINDOW HEIGHT ) ) ; break ; // w y j ś c i e case EXIT : e x i t ( 0 ) ; int main ( int argc, char argv [ ] ) // i n i c j a l i z a c j a b i b l i o t e k i GLUT g l u t I n i t (& argc, argv ) ; // i n i c j a l i z a c j a b u f o r a ramki g l u t I n i t D i s p l a y M o d e (GLUT DOUBLE GLUT RGB ) ; // r o z m i a r y g ł ó w n e g o okna programu g l u t I n i t W i n d o w S i z e ( 4 0 0, 4 0 0 ) ; // u t w o r z e n i e g ł ó w n e g o okna programu glutcreatewindow ( S z e ś c i a n 2 ) ; // d o ł ą c z e n i e f u n k c j i g e n e r u j ą c e j s c e n ę 3D glutdisplayfunc ( Display ) ; // d o ł ą c z e n i e f u n k c j i wywoływanej p r z y z m i a n i e r o z m i a r u okna glutreshapefunc ( Reshape ) ; // u t w o r z e n i e menu p o d r ę c z n e g o glutcreatemenu ( Menu ) ; // d o d a n i e p o z y c j i do menu p o d r ę c z n e g o glutaddmenuentry ( Aspekt obrazu całe okno,full WINDOW) ; glutaddmenuentry ( Aspekt obrazu 1 : 1, ASPECT 1 1 ) ; glutaddmenuentry ( Wyjście,EXIT ) ; // o k r e ś l e n i e p r z y c i s k u m y s z k i o b s ł u g u j ą c e j menu p o d r ę c z n e glutattachmenu (GLUT RIGHT BUTTON ) ; // w p r o w a d z e n i e programu do o b s ł u g i p ę t l i komunikatów glutmainloop ( ) ; return 0 ; Drugi program przedstawiający rzutowanie perspektywiczne (plik szescian3.cpp) stosuje funkcję gluperspective. Aby jednak nie powielać rozwiązań z poprzedniego programu dodamy mechanizm pokazujący jaki wpływ na wygląd obiektów 3D ma zmiana położenie środka perspektywy, realizowana poprzez zmianę kąta widzenia obserwatora (parametr fovy funkcji gluperspective). W tym celu potrzebna jest obsługa klawiatury. Podstawo-
1. Definiowanie sceny 3D 16 wa funkcja obsługi klawiatury (w przykładowym programie jest to funkcja Keyboard) ma trzy parametry: key - kod ASCII klawisza, x, y - współrzędne kursora myszki w chwili naciśnięcia przycisku klawiatury. Aby obsługa klawiatury działała, w części głównej programu należy włączyć funkcję obsługi klawiatury wywołując funkcję: void glutkeyboardfunc (void (*func)(unsigned char key, int x, int y)) Początkowe okno programu Sześcian 3 zawiera rysunek 7. Przyciskając klawisze + i - można modyfikować kąt patrzenia obserwatora, który początkowo wynosi 90. Rysunek 7. Początkowe okno programu Sześcian 3 1.3.2. Plik szescian3.cpp / ( c ) Janusz G a n c z a r s k i h t t p : / /www. j a n u s z g. hg. p l JanuszG@enter. n e t. p l /
1. Definiowanie sceny 3D 17 #include <GL/ glut. h> #include < s t d l i b. h> // s t a ł a do o b s ł u g i menu p o d r ę c z n e g o enum EXIT // w y j ś c i e ; // pionowy k ą t p o l a w i d z e n i a GLdouble f o v y = 9 0 ; // f u n k c j a g e n e r u j ą c a s c e n ę 3D void D i s p l a y ( ) // k o l o r t ł a z a w a r t o ś ć b u f o r a k o l o r u g l C l e a r C o l o r ( 1. 0, 1. 0, 1. 0, 1. 0 ) ; // c z y s z c z e n i e b u f o r a k o l o r u g l C l e a r ( GL COLOR BUFFER BIT ) ; // wybór m a c i e r z y modelowania glmatrixmode (GL MODELVIEW) ; // m a c i e r z modelowania = m a c i e r z j e d n o s t k o w a g l L o a d I d e n t i t y ( ) ; // p r z e s u n i ę c i e o b i e k t u o w e k t o r [ 0, 0, 3 ] g l T r a n s l a t e f ( 0, 0, 3. 0 ) ; // k o l o r k r a w ę d z i s z e ś c i a n u g l C o l o r 3 f ( 0. 0, 0. 0, 0. 0 ) ; // p o c z ą t e k d e f i n i c j i k r a w ę d z i s z e ś c i a n u g l B e g i n ( GL LINES ) ; // w s p ó l r z ę d n e k o l e j n y c h k r a w ę d z i s z e ś c i a n u g l V e r t e x 3 f ( 1. 0, 1. 0, 1. 0 ) ; g l V e r t e x 3 f ( 1. 0, 1. 0, 1. 0 ) ; g l V e r t e x 3 f ( 1. 0, 1. 0, 1. 0 ) ; g l V e r t e x 3 f ( 1. 0, 1. 0, 1. 0 ) ; g l V e r t e x 3 f ( 1. 0, 1. 0, 1. 0 ) ; g l V e r t e x 3 f ( 1. 0, 1. 0, 1. 0 ) ; g l V e r t e x 3 f ( 1. 0, 1. 0, 1. 0 ) ; g l V e r t e x 3 f ( 1. 0, 1. 0, 1. 0 ) ; g l V e r t e x 3 f ( 1. 0, 1. 0, 1. 0 ) ; g l V e r t e x 3 f ( 1. 0, 1. 0, 1. 0 ) ; g l V e r t e x 3 f ( 1. 0, 1. 0, 1. 0 ) ; g l V e r t e x 3 f ( 1. 0, 1. 0, 1. 0 ) ; g l V e r t e x 3 f ( 1. 0, 1. 0, 1. 0 ) ; g l V e r t e x 3 f ( 1. 0, 1. 0, 1. 0 ) ; g l V e r t e x 3 f ( 1. 0, 1. 0, 1. 0 ) ; g l V e r t e x 3 f ( 1. 0, 1. 0, 1. 0 ) ; g l V e r t e x 3 f ( 1. 0, 1. 0, 1. 0 ) ; g l V e r t e x 3 f ( 1. 0, 1. 0, 1. 0 ) ; g l V e r t e x 3 f ( 1. 0, 1. 0, 1. 0 ) ; g l V e r t e x 3 f ( 1. 0, 1. 0, 1. 0 ) ; g l V e r t e x 3 f ( 1. 0, 1. 0, 1. 0 ) ; g l V e r t e x 3 f ( 1. 0, 1. 0, 1. 0 ) ; g l V e r t e x 3 f ( 1. 0, 1. 0, 1. 0 ) ; g l V e r t e x 3 f ( 1. 0, 1. 0, 1. 0 ) ; // k o n i e c d e f i n i c j i prymitywu glend ( ) ;
1. Definiowanie sceny 3D 18 // s k i e r o w a n i e p o l e c e ń do wykonania g l F l u s h ( ) ; // zamiana b u f o r ó w k o l o r u glutswapbuffers ( ) ; // zmiana w i e l k o ś c i okna void Reshape ( int width, int h e i g h t ) // o b s z a r r e n d e r i n g u c a ł e okno g l V i e w p o r t ( 0, 0, width, h e i g h t ) ; // wybór m a c i e r z y r z u t o w a n i a glmatrixmode ( GL PROJECTION ) ; // m a c i e r z r z u t o w a n i a = m a c i e r z j e d n o s t k o w a g l L o a d I d e n t i t y ( ) ; // o b l i c z e n i e a s p e k t u o b r a z u z u w z g l ę d n i e n i e m // przypadku, gdy wysokość obrazu wynosi 0 GLdouble a s p e c t = 1 ; i f ( h e i g h t > 0) aspect = width / ( GLdouble ) height ; // r z u t o w a n i e p e r s p e k t y w i c z n e g l u P e r s p e c t i v e ( fovy, a s p e c t, 1. 0, 5. 0 ) ; // g e n e r o w a n i e s c e n y 3D D i s p l a y ( ) ; // o b s ł u g a k l a w i a t u r y void Keyboard ( unsigned char key, int x, int y ) // k l a w i s z + i f ( key == + && f o v y < 180) f o v y++; e l s e // k l a w i s z i f ( key == && f o v y > 0) fovy ; // o d r y s o w a n i e okna Reshape ( glutget (GLUT WINDOW WIDTH), glutget (GLUT WINDOW HEIGHT ) ) ; // ob sług a menu podręcznego void Menu ( int v a l u e ) switch ( v a l u e ) // w y j ś c i e case EXIT : e x i t ( 0 ) ; int main ( int argc, char argv [ ] ) // i n i c j a l i z a c j a b i b l i o t e k i GLUT g l u t I n i t (& argc, argv ) ; // i n i c j a l i z a c j a b u f o r a ramki g l u t I n i t D i s p l a y M o d e (GLUT DOUBLE GLUT RGB ) ; // r o z m i a r y g ł ó w n e g o okna programu g l u t I n i t W i n d o w S i z e ( 4 0 0, 4 0 0 ) ; // u t w o r z e n i e g ł ó w n e g o okna programu glutcreatewindow ( S z e ś c i a n 3 ) ; // d o ł ą c z e n i e f u n k c j i g e n e r u j ą c e j s c e n ę 3D glutdisplayfunc ( Display ) ; // d o ł ą c z e n i e f u n k c j i wywoływanej p r z y z m i a n i e r o z m i a r u okna
1. Definiowanie sceny 3D 19 glutreshapefunc ( Reshape ) ; // d o ł ą c z e n i e f u n k c j i o b s ł u g i k l a w i a t u r y glutkeyboardfunc ( Keyboard ) ; // u t w o r z e n i e menu p o d r ę c z n e g o glutcreatemenu ( Menu ) ; // d o d a n i e p o z y c j i do menu p o d r ę c z n e g o glutaddmenuentry ( Wyjście,EXIT ) ; // o k r e ś l e n i e p r z y c i s k u m y s z k i o b s ł u g u j ą c e j menu p o d r ę c z n e glutattachmenu (GLUT RIGHT BUTTON ) ; // w p r o w a d z e n i e programu do o b s ł u g i p ę t l i komunikatów glutmainloop ( ) ; return 0 ; 1.4. Położenie obserwatora Ostatnim z podstawowych elementów wymagających omówienia przy tworzeniu sceny 3D jest położenie obserwatora, nazywane także położeniem kamery lub oka. Domyślnie obserwator w OpenGL położony jest w początku układu współrzędnych i skierowany jest w stronę ujemnej półosi OZ. Obserwator jest tak zorientowany w przestrzeni, że kierunek do góry pokrywa się z kierunkiem osi OY. Zasadniczo OpenGL nie umożliwia zmiany położenia obserwatora. Wszystkie przekształcenia położenia obserwatora faktycznie realizowane są jako odpowiednie przekształcenia układu współrzędnych. Aby jednak ułatwić prace związane z definiowaniem tych przekształceń, biblioteka GLU zawiera funkcję glulookat, która pozwala na jednorazowe zdefiniowanie wszystkich parametrów opisujących obserwatora: void glulookat (GLdouble eyex, GLdouble eyey, GLdouble eyez, GLdouble centerx, GLdouble centery, GLdouble centerz, GLdouble upx, GLdouble upy, GLdouble upz) Kolejne trójki parametrów funkcji glulookat oznaczają: eyex, eyey, eyez - współrzędne położenia obserwatora, centerx, centery, centerz - współrzędne punktu, w którego kierunku jest zwrócony obserwator, upx, upy, upz - współrzędne wektora określającego kierunek do góry. Domyślne położenie obserwatora odpowiada wywołaniu glulookat (0.0, 0.0, 0.0, 0.0, 0.0, -100.0, 0.0, 1.0, 0.0). W kolejnym przykładowym programie (plik szescian4.cpp) będziemy modyfikować tylko współrzędne położenia obserwatora. Przy niezmiennych współrzędnych punktu, w którego kierunku patrzy obserwator, daje to ciekawy efekt obserwacji sceny z pewnej odległości. Zmiana położenia obserwatora realizowana jest w funkcjach Keyboard (przyciski + i - ) oraz SpecialKeys (klawisze kursora). Warto zauwa-
1. Definiowanie sceny 3D 20 żyć, że zmiany współrzędnych obserwatora, które reprezentują zmienne eyex, eyey i eyez, są odwrotne niż można by się spodziewać. Przykładowo naciśnięcie strzałki w dół powoduje zwiększenie o 0,1 zmiennej eyey, która określa współrzędną Y położenia obserwatora. Jest to spowodowane tym, że macierz modelowania, modyfikowana przy wywołaniu funkcji glulookat, odgrywa podwójną rolę. Z jednej strony umożliwia przekształcenia współrzędnych obiektu (patrz poprzedni przykład), a z drugiej przekształcenia współrzędnych obserwatora. Przykładowo, to co z punktu widzenia obiektu jest przesunięciem o wektor [1, 0, 0], dla obserwatora jest przesunięciem o wektor przeciwny tj. [ 1, 0, 0]. Dobre poznanie opisanego mechanizmy wymaga eksperymentów, do których gorąco zachęcam Czytelników. Do omówienia pozostała wprowadzona w ostatnim przykładzie obsługa klawiszy kursora. Jest ona realizowana odrębnie od obsługi przycisków, które reprezentowane są bezpośrednio przez kody ASCII (funkcja Keyboard). Funkcja obsługująca klawisze kursora oraz przyciski funkcyjne (w przykładowym programie jest to funkcja SpecialKeys) ma trzy parametry: key - kod przycisku; zwracana jest jedna z poniższych wartości: GLUT KEY F1 - przycisk F1, GLUT KEY F2 - przycisk F2, GLUT KEY F3 - przycisk F3, GLUT KEY F4 - przycisk F4, GLUT KEY F5 - przycisk F5, GLUT KEY F6 - przycisk F6, GLUT KEY F7 - przycisk F7, GLUT KEY F8 - przycisk F8, GLUT KEY F9 - przycisk F9, GLUT KEY F10 - przycisk F10, GLUT KEY F11 - przycisk F11, GLUT KEY F12 - przycisk F12, GLUT KEY LEFT - kursor w lewo, GLUT KEY UP - kursor do góry, GLUT KEY RIGHT - kursor w prawo, GLUT KEY DOWN - kursor w dół, GLUT KEY PAGE UP - przycisk Page Up GLUT KEY PAGE DOWN - przycisk Page Down, GLUT KEY HOME - przycisk Home, GLUT KEY END - przycisk End, GLUT KEY INSERT - przycisk Insert. x, y - współrzędne kursora myszki w chwili naciśnięcia przycisku klawiatury. Podobnie jak w przypadku poprzedniej funkcji obsługującej klawiaturę,
1. Definiowanie sceny 3D 21 w głównym programie należy włączyć obsługę klawiszy kursora i klawiszy funkcyjnych wywołując funkcję: void glutspecialfunc (void (*func)(int key, int x, int y)) Rysunek 8 przedstawia przykładowe okno programu Sześcian 4, którego kod źródłowy znajduje się poniżej. Rysunek 8. Przykładowe okno programu Sześcian 4 1.4.1. Plik szescian4.cpp / ( c ) Janusz G a n c z a r s k i h t t p : / /www. j a n u s z g. hg. p l JanuszG@enter. n e t. p l / #include <GL/ glut. h> #include < s t d l i b. h> // s t a ł e do o b s ł u g i menu p o d r ę c z n e g o enum FULL WINDOW, // a s p e k t o b r a z u c a ł e okno ASPECT 1 1, // a s p e k t o b r a z u 1 : 1 EXIT // w y j ś c i e ; // a s p e k t o b r a z u
1. Definiowanie sceny 3D 22 int Aspect = FULL WINDOW; // w p ó ł r z ę d n e p o ł o ż e n i a o b s e r w a t o r a GLdouble eyex = 0 ; GLdouble eyey = 0 ; GLdouble e y e z = 3 ; // współrzędne punktu w k t ó r e g o kierunku j e s t zwrócony obserwator, GLdouble c e n t e r x = 0 ; GLdouble c e n t e r y = 0 ; GLdouble c e n t e r z = 100; // f u n k c j a g e n e r u j ą c a s c e n ę 3D void D i s p l a y ( ) // k o l o r t ł a z a w a r t o ś ć b u f o r a k o l o r u g l C l e a r C o l o r ( 1. 0, 1. 0, 1. 0, 1. 0 ) ; // c z y s z c z e n i e b u f o r a k o l o r u g l C l e a r ( GL COLOR BUFFER BIT ) ; // wybór m a c i e r z y modelowania glmatrixmode (GL MODELVIEW) ; // m a c i e r z modelowania = m a c i e r z j e d n o s t k o w a g l L o a d I d e n t i t y ( ) ; // u s t a w i e n i e o b s e r w a t o r a glulookat ( eyex, eyey, eyez, c e n t e r x, c e n t e r y, c e n t e r z, 0, 1, 0 ) ; // k o l o r k r a w ę d z i s z e ś c i a n u g l C o l o r 3 f ( 0. 0, 0. 0, 0. 0 ) ; // p o c z ą t e k d e f i n i c j i k r a w ę d z i s z e ś c i a n u g l B e g i n ( GL LINES ) ; // w s p ó l r z ę d n e k o l e j n y c h k r a w ę d z i s z e ś c i a n u g l V e r t e x 3 f ( 1. 0, 1. 0, 1. 0 ) ; g l V e r t e x 3 f ( 1. 0, 1. 0, 1. 0 ) ; g l V e r t e x 3 f ( 1. 0, 1. 0, 1. 0 ) ; g l V e r t e x 3 f ( 1. 0, 1. 0, 1. 0 ) ; g l V e r t e x 3 f ( 1. 0, 1. 0, 1. 0 ) ; g l V e r t e x 3 f ( 1. 0, 1. 0, 1. 0 ) ; g l V e r t e x 3 f ( 1. 0, 1. 0, 1. 0 ) ; g l V e r t e x 3 f ( 1. 0, 1. 0, 1. 0 ) ; g l V e r t e x 3 f ( 1. 0, 1. 0, 1. 0 ) ; g l V e r t e x 3 f ( 1. 0, 1. 0, 1. 0 ) ; g l V e r t e x 3 f ( 1. 0, 1. 0, 1. 0 ) ; g l V e r t e x 3 f ( 1. 0, 1. 0, 1. 0 ) ; g l V e r t e x 3 f ( 1. 0, 1. 0, 1. 0 ) ; g l V e r t e x 3 f ( 1. 0, 1. 0, 1. 0 ) ; g l V e r t e x 3 f ( 1. 0, 1. 0, 1. 0 ) ; g l V e r t e x 3 f ( 1. 0, 1. 0, 1. 0 ) ; g l V e r t e x 3 f ( 1. 0, 1. 0, 1. 0 ) ; g l V e r t e x 3 f ( 1. 0, 1. 0, 1. 0 ) ; g l V e r t e x 3 f ( 1. 0, 1. 0, 1. 0 ) ; g l V e r t e x 3 f ( 1. 0, 1. 0, 1. 0 ) ; g l V e r t e x 3 f ( 1. 0, 1. 0, 1. 0 ) ; g l V e r t e x 3 f ( 1. 0, 1. 0, 1. 0 ) ; g l V e r t e x 3 f ( 1. 0, 1. 0, 1. 0 ) ; g l V e r t e x 3 f ( 1. 0, 1. 0, 1. 0 ) ; // k o n i e c d e f i n i c j i prymitywu glend ( ) ;
1. Definiowanie sceny 3D 23 // s k i e r o w a n i e p o l e c e ń do wykonania g l F l u s h ( ) ; // zamiana b u f o r ó w k o l o r u glutswapbuffers ( ) ; // zmiana w i e l k o ś c i okna void Reshape ( int width, int h e i g h t ) // o b s z a r r e n d e r i n g u c a ł e okno g l V i e w p o r t ( 0, 0, width, h e i g h t ) ; // wybór m a c i e r z y r z u t o w a n i a glmatrixmode ( GL PROJECTION ) ; // m a c i e r z r z u t o w a n i a = m a c i e r z j e d n o s t k o w a g l L o a d I d e n t i t y ( ) ; // p a r a m e t r y b r y ł y o b c i n a n i a i f ( Aspect == ASPECT 1 1 ) // w y s o k o ś ć okna w i ę k s z a od w y s o k o ś c i okna i f ( width < h e i g h t && width > 0) glfrustum ( 2. 0, 2. 0, 2. 0 h e i g h t / width, 2. 0 h e i g h t / width, 1. 0, 5. 0 ) ; e l s e // s z e r o k o ś ć okna w i ę k s z a l u b równa w y s o k o ś c i okna i f ( width >= h e i g h t && h e i g h t > 0) glfrustum ( 2.0 width / h e i g h t, 2. 0 width / h e i g h t, 2. 0, 2. 0, 1. 0, 5. 0 ) ; e l s e glfrustum ( 2. 0, 2. 0, 2. 0, 2. 0, 1. 0, 5. 0 ) ; // g e n e r o w a n i e s c e n y 3D D i s p l a y ( ) ; // o b s ł u g a k l a w i a t u r y void Keyboard ( unsigned char key, int x, int y ) // k l a w i s z + i f ( key == + ) e y e z = 0.1; e l s e // k l a w i s z i f ( key == ) e y e z + = 0. 1 ; // o d r y s o w a n i e okna Reshape ( glutget (GLUT WINDOW WIDTH), glutget (GLUT WINDOW HEIGHT ) ) ; // o b s ł u g a k l a w i s z y f u n k c y j n y c h i k l a w i s z y k u r s o r a void SpecialKeys ( int key, int x, int y ) switch ( key ) // k u r s o r w l e w o case GLUT KEY LEFT : eyex + = 0. 1 ; break ; // k u r s o r w g ó r ę case GLUT KEY UP : eyey = 0.1; break ; // k u r s o r w prawo case GLUT KEY RIGHT : eyex = 0.1; break ; // k u r s o r w d ó ł case GLUT KEY DOWN: eyey + = 0. 1 ;
1. Definiowanie sceny 3D 24 break ; // o d r y s o w a n i e okna Reshape ( glutget (GLUT WINDOW WIDTH), glutget (GLUT WINDOW HEIGHT ) ) ; // ob sług a menu podręcznego void Menu ( int v a l u e ) switch ( v a l u e ) // o b s z a r r e n d e r i n g u c a ł e okno case FULL WINDOW: Aspect = FULL WINDOW; Reshape ( glutget (GLUT WINDOW WIDTH), glutget (GLUT WINDOW HEIGHT ) ) ; break ; // o b s z a r r e n d e r i n g u a s p e k t 1 : 1 case ASPECT 1 1 : Aspect = ASPECT 1 1 ; Reshape ( glutget (GLUT WINDOW WIDTH), glutget (GLUT WINDOW HEIGHT ) ) ; break ; // w y j ś c i e case EXIT : e x i t ( 0 ) ; int main ( int argc, char argv [ ] ) // i n i c j a l i z a c j a b i b l i o t e k i GLUT g l u t I n i t (& argc, argv ) ; // i n i c j a l i z a c j a b u f o r a ramki g l u t I n i t D i s p l a y M o d e (GLUT DOUBLE GLUT RGB ) ; // r o z m i a r y g ł ó w n e g o okna programu g l u t I n i t W i n d o w S i z e ( 4 0 0, 4 0 0 ) ; // u t w o r z e n i e g ł ó w n e g o okna programu glutcreatewindow ( S z e ś c i a n 4 ) ; // d o ł ą c z e n i e f u n k c j i g e n e r u j ą c e j s c e n ę 3D glutdisplayfunc ( Display ) ; // d o ł ą c z e n i e f u n k c j i wywoływanej p r z y z m i a n i e r o z m i a r u okna glutreshapefunc ( Reshape ) ; // d o ł ą c z e n i e f u n k c j i o b s ł u g i k l a w i a t u r y glutkeyboardfunc ( Keyboard ) ; // d o ł ą c z e n i e f u n k c j i o b s ł u g i k l a w i s z y f u n k c y j n y c h i k l a w i s z y k u r s o r a glutspecialfunc ( SpecialKeys ) ; // u t w o r z e n i e menu p o d r ę c z n e g o glutcreatemenu ( Menu ) ; // d o d a n i e p o z y c j i do menu p o d r ę c z n e g o glutaddmenuentry ( Aspekt obrazu całe okno,full WINDOW) ; glutaddmenuentry ( Aspekt obrazu 1 : 1, ASPECT 1 1 ) ; glutaddmenuentry ( Wyjście,EXIT ) ; // o k r e ś l e n i e p r z y c i s k u m y s z k i o b s ł u g u j ą c e j menu p o d r ę c z n e glutattachmenu (GLUT RIGHT BUTTON ) ; // w p r o w a d z e n i e programu do o b s ł u g i p ę t l i komunikatów glutmainloop ( ) ; return 0 ;
Literatura 25 Literatura [1] Mark Segal, Kurt Akeley: The OpenGL Graphics System. A Specification Version 2.0 [2] Jackie Neider, Tom Davis, Mason Woo: OpenGL Programming Guide The Red Book [3] Richard S. Wright jr, Michael Sweet: OpenGL Księga eksperta, Helion 1999 [4] The official OpenGL web page, http://www.opengl.org [5] Piotr andrzejewski, Jakub Kurzak: Wprowadzenie do OpenGL. Programowanie zastosowań graficznych, Kwantum 2000