Janusz Ganczarski
OpenGL
Przekształcenia geometryczne
Spis treści
Spis treści . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1
1. Przekształcenia geometryczne . . . . . . . . . . . . . . . . . . . . . .
1
Obrót . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1
Skalowanie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2
Mnożenie macierzy . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2
Ładowanie macierzy . . . . . . . . . . . . . . . . . . . . . . . . . . .
2
Składanie przekształceń . . . . . . . . . . . . . . . . . . . . . . . . .
3
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3
. . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3
Torus . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4
Dwunastościan . . . . . . . . . . . . . . . . . . . . . . . . . .
5
Czajnik . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
5
Ośmiościan . . . . . . . . . . . . . . . . . . . . . . . . . . . .
5
Czworościan . . . . . . . . . . . . . . . . . . . . . . . . . . .
6
Dwudziestościan . . . . . . . . . . . . . . . . . . . . . . . . .
6
1.6.10. Obsługa myszki . . . . . . . . . . . . . . . . . . . . . . . . .
6
1.6.11. Menu wielopoziomowe . . . . . . . . . . . . . . . . . . . . . .
8
1.6.12. Odrysowanie okna . . . . . . . . . . . . . . . . . . . . . . . .
8
1.6.13. Plik przeksztalcenia.cpp . . . . . . . . . . . . . . . . . . . . .
8
Stos macierzy modelowania . . . . . . . . . . . . . . . . . . . . . . .
14
Operacje na stosie . . . . . . . . . . . . . . . . . . . . . . . .
14
Plik stos modelowania.cpp . . . . . . . . . . . . . . . . . . .
18
Literatura . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
24
1. Przekształcenia geometryczne
W tym odcinku kursu poznamy mechanizmy biblioteki OpenGL umoż-
liwiające dowolne przekształcenia geometryczne obiektów. Wykorzystamy
także stos macierzy w celu modelowania sceny 3D zawierającej wiele ele-
mentów.
1.1. Obrót
Obrót w OpenGL wykonują funkcje glRotated i glRotatef:
void glRotated (GLdouble angle,
GLdouble x, GLdouble y, GLdouble z)
void glRotatef (GLfloat angle,
GLfloat x, GLfloat y, GLfloat z)
których parametry oznaczają:
— angle - kąt obrotu w stopniach,
— x, y, z - współrzędne wektora określającego oś obrotu.
Obrót realizowany jest w kierunku przeciwnym do ruchu wskazówek zega-
ra w kierunku prostej wyznaczonej przez wektor [x, y, z] zaczepionym w po-
czątku układu współrzędnych. Jeżeli wektor ma długość różną od 1 wektor
jest normalizowany.
Funkcje glRotated i glRotatef mnożą bieżącą macierz przez przez ma-
cierz obrotu, która ma następującą postać (parametr angle zamieniono
na a):
x
2
(1 − cos a) + cos a
xy (1 − cos a) − z sin a
xz (1 − cos a) + y sin a
0
yx (1 − cos a) + z sin a
y
2
(1 − cos a) + cos a
yz (1 − cos a) − x sin a
0
xz (1 − cos a) − y sin a
yz (1 − cos a) + x sin a
z
2
(1 − cos a) + cos a
0
0
0
0
1
1.2. Skalowanie
Skalowanie wykonują następujące funkcje:
void glScalef (GLfloat x, GLfloat y, GLfloat z)
void glScalex (GLfixed x, GLfixed y, GLfixed z)
gdzie x, y, z są współczynnikami skalowania względem kolejnych osi układu
współrzędnych. Funkcje te mnożą bieżącą macierz przez macierz skalowania,
która ma postać:
x
0
0
0
0
y
0
0
0
0
z
0
0
0
0
1
1. Przekształcenia geometryczne
2
1.3. Przesunięcie
Trzecią z podstawowych operacji geometrycznych jest przesunięcie o wek-
tor (transalcja), którą realizują funkcje:
void glTranslatef (GLfloat x, GLfloat y, GLfloat z)
void glTranslatex (GLfixed x, GLfixed y, GLfixed z)
gdzie x, y, z są współrzędnymi wektora przesunięcia. Podobnie jak poprzed-
nio opisane funkcje, glTranslatef i glTranslatex mnożą bieżącą macierz
przez macierz translacji, która ma postać:
1
0
0
x
0
1
0
y
0
0
1
z
0
0
0
1
1.4. Mnożenie macierzy
W przypadku, gdy zestaw standardowych przekształceń macierzowych
okazuje się niewystarczający, biblioteka OpenGL udostępnia możliwość prze-
mnożenia bieżącej macierzy przez macierz określoną funkcją z grupy glMult-
Matrix:
void glMultMatrixd (const GLdouble *m)
void glMultMatrixf (const GLfloat *m)
Parametr m obu funkcji zawiera wskaźnik na dane macierzy o rozmia-
rach 4 × 4, które muszą być ułożone kolejno kolumnami, tj. w kolejności
transponowanej w stosunku do przyjętej w językach C i C++:
a
0
a
4
a
8
a
12
a
1
a
5
a
9
a
13
a
2
a
6
a
10
a
14
a
3
a
7
a
11
a
15
1.5. Ładowanie macierzy
Ostatnią z opisywanych operacji na macierzach jest zastępowanie bieżą-
cej macierzy przez dowolnie określoną macierz o rozmiarach 4 × 4. Operację
tę wykonują funkcje z grupy glLoadMatrix:
void glLoadMatrixd (const GLdouble *m)
void glLoadMatrixf (const GLfloat *m)
Format danych ładowanej macierzy jest taki sam jak w przedstawionych
wyżej funkcjach glMultMatrixd i glMultMatrixf.
1. Przekształcenia geometryczne
3
1.6. Składanie przekształceń
Macierzowy opis przekształceń geometrycznych znacznie ułatwia skła-
danie kilku różnych przekształceń obiektów. Wywołując funkcje generujące
macierze odpowiednich przekształceń dokonujemy jednocześnie ich składa-
nia. W tej sytuacji jedyną rzeczą, o której należy pamiętać, to kolejność
przekształceń, bowiem od tego zależy końcowy efekt.
Przykładowy program (plik przeksztalcenia.cpp) przedstawia prze-
kształcenia geometryczne dostępne w bibliotece OpenGL. Scena 3D zawiera
pojedynczy obiekt geometryczny zawarty w bibliotece GLUT. Klawisze kur-
sora pozwalają na obracanie wyświetlanego obiektu, przyciski „+” i „-” na
jego skalowanie, a lewy przycisk myszki przesuwa obiekt. W ramach ekspe-
rymentu Czytelnik może w programie zamienić kolejność składania wyko-
nywanych tam przekształceń (funkcja Display) np. przesunięcia i obrotu.
Poznajmy jeszcze nowe elementy biblioteki GLUT wykorzystanie w przy-
kładowym programie tj. sposób obsługi myszki i zdefiniowane obiekty geo-
metryczne. Biblioteka GLUT udostępnia obiekty 3D w wersji szkieletowej
(tzw. „druciaki”) oraz w wersji pełnej. W najbliższych przykładowych pro-
gramach wykorzystamy wersje szkieletowe obiektów.
1.6.1. Kula
Powierzchnia kuli rysowana jest jako szkielet składający się z południków
i równoleżników (rysunek 1). Powierzchnię kuli, której środek znajduje się
w początku układu współrzędnych rysuje funkcja:
void glutWireSphere (GLdouble radius, GLint slices, GLint stacks)
której parametry oznaczają:
— radius - promień kuli,
— slices - ilość południków,
— stacks - ilość równoleżników.
1.6.2. Sześcian
Sześcian o boku długości size i środku położonym w początku układu
współrzędnych rysuje funkcja:
void glutWireCube (GLdouble size)
1.6.3. Stożek
Stożek rysowany jest podobnie jak kula - jako szkielet oparty na równo-
ległe do podstawy „południki” i tworzące biegnące od wierzchołka stożka do
krawędzi jego podstawy (rysunek 2). Stożek ze środkiem podstawy umiesz-
czonym w początku układu współrzędnych i wierzchołkiem umieszczonym
na dodatniej półosi OZ rysuje funkcja:
1. Przekształcenia geometryczne
4
Rysunek 1. Program Przekształcenia - kula
void glutWireCone (GLdouble base, GLdouble height,
GLint slices, GLint stacks)
której parametry oznaczają:
— base - promień podstawy stożka,
— height - wysokość stożka,
— slices - ilość tworzących,
— stacks - ilość „południków”.
1.6.4. Torus
Kolejna bryłą obrotową dostępną w bibliotece GLUT jest torus rysowany
jako seria walców o nierównoległych podstawach (rysunek 3) i osi obrotu
pokrywającej się z osią OZ. Torus rysuje funkcja:
void glutWireTorus (GLdouble innerRadius, GLdouble outerRadius,
GLint sides, GLint rings)
której parametry oznaczają odpowiednio:
— innerRadius - promień koła tworzącego torus,
— outerRadius - promień torusa,
1. Przekształcenia geometryczne
5
Rysunek 2. Program Przekształcenia - stożek
— sides - ilość ścian bocznych, z których składa się pojedynczy walec,
— rings - ilość walców, z których składa się torus.
1.6.5. Dwunastościan
Dwunastościan o środku położonym w początku układu współrzędnych
rysuje funkcja:
void glutWireDodecahedron (void)
1.6.6. Czajnik
Klasycznym obiektem 3D dostępnym w bibliotece GLUT jest opracowa-
ny w 1975 roku przez Martina Newella czajnik - przedstawiony na rysunku 4.
Czajnik o wielkości regulowanej parametrem size rysuje funkcja:
void glutWireTeapot (GLdouble size)
1.6.7. Ośmiościan
Ośmiościan o środku położonym w początku układu współrzędnych ry-
suje funkcja:
1. Przekształcenia geometryczne
6
Rysunek 3. Program Przekształcenia - torus
void glutWireOctahedron (void)
1.6.8. Czworościan
Czworościan o środku położonym w początku układu współrzędnych ry-
suje funkcja:
void glutWireTetrahedron (void)
1.6.9. Dwudziestościan
Dwudziestościan o środku położonym w początku układu współrzędnych
rysuje funkcja:
void glutWireIcosahedron (void)
1.6.10. Obsługa myszki
Obsługa myszki składa się z dwóch etapów i jest wykonywana przez dwie
funkcje. Pierwsza z nich to:
void MouseButton (int button, int state, int x, int y)
1. Przekształcenia geometryczne
7
Rysunek 4. Program Przekształcenia - czajnik
która wykrywa naciśnięcie i zwolnienie lewego przycisku myszki. W zależ-
ności od stanu lewego przycisku myszki ustawiana jest wartość zmiennej
globalnej button state na przekazaną przez parametr state. Druga funk-
cja:
void MouseMotion (int x, int y)
wywoływana jest podczas ruchu kursora myszki a jej zadaniem jest odpo-
wiednie (dobrane częściowo doświadczalnie) przeliczenie ruchu myszki na
przesunięcie obiektu znajdującego się na scenie. Efekt przeliczeń ruchu kur-
sora myszki umieszczony jest w zmiennych globalnych translatex i trans-
latey, które są bezpośredni przekazywane jako parametry funkcji glTrans-
latef.
Parametry x i y obu funkcji oznaczają współrzędne kursora myszki w od-
niesieniu do układu współrzędnych okna, które oczywiście nie mają nic
wspólnego ze współrzędnymi określonymi w scenie 3D. Parametr button
funkcji MouseButton określa który przycisk myszki został naciśnięty lub
zwolniony. Parametr ten przyjmuje jedną z wartości:
— GLUT LEFT BUTTON - lewy przycisk myszki,
1. Przekształcenia geometryczne
8
— GLUT MIDDLE BUTTON - środkowy przycisk myszki,
— GLUT RIGHT BUTTON - prawy przycisk myszki.
Jeżeli w danym systemie myszka ma tylko dwa przyciski, wartość GLUT MID-
DLE BUTTON nie będzie generowana. Natomiast w przypadku myszki z jed-
nym przyciskiem funkcja generuje jedynie wartość GLUT LEFT BUTTON. Ostat-
ni nieopisany parametr funkcji MouseButton to state, który określa czy
przycisk myszki został naciśnięty (stała GLUT UP) czy zwolniony (stała GLUT -
DOWN).
Aby opisane funkcje obsługi myszki działały należy je dołączyć do listy
funkcji zwrotnych wywołując odpowiednio:
void glutMouseFunc (void (*func)(int button, int state,
int x, int y))
void glutMotionFunc (void (*func)(int x, int y))
1.6.11. Menu wielopoziomowe
W programie został użyty nowy element biblioteki GLUT — wielopo-
ziomowe menu podręczne. Część menu podręcznego, które będzie znajdo-
wało się na drugim (lub wyższym) poziomie tworzymy w taki sam spo-
sób jak dotychczas tworzyliśmy główne menu, czyli przy użyciu funkcji
glutCreateMenu i glutAddMenuEntry. Tak utworzony fragment menu umiesz-
czamy w menu głównym (nadrzędnym) używając funkcji:
void glutAddSubMenu (const char *label, int submenu)
Parametr label określa nazwę menu podręcznego, a submenu jego identyfi-
kator zwrócony przez funkcję glutCreateMenu.
1.6.12. Odrysowanie okna
Aby zmiany sceny 3D zostały wyświetlone na ekranie potrzebne jest
odrysowanie bieżącego okna. Można to zrealizować wywołując funkcję:
void glutPostRedisplay (void)
1.6.13. Plik przeksztalcenia.cpp
/∗
( c )
J a n u s z
G a n c z a r s k i
h t t p : / / www . j a n u s z g . h g . p l
J a n u s z G @ e n t e r . n e t . p l
∗/
#i n c l u d e <GL/ g l u t . h>
#i n c l u d e < 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
o k n o
ASPECT 1 1 ,
//
a s p e k t
o b r a z u
1 : 1
WIRE SPHERE ,
//
k u l a
1. Przekształcenia geometryczne
9
WIRE CONE,
//
s t o ż e k
WIRE CUBE,
//
s z e ś c i a n
WIRE TORUS,
//
t o r u s
WIRE DODECAHEDRON,
//
d w u n a s t o ś c i a n
WIRE TEAPOT,
//
c z a j n i k
WIRE OCTAHEDRON,
//
o ś m i o ś c i a n
WIRE TETRAHEDRON,
//
c z w o r o ś c i a n
WIRE ICOSAHEDRON,
//
d w u d z i e s t o ś c i a n
EXIT
//
w y j ś c i e
} ;
//
a s p e k t
o b r a z u
i n t
a s p e c t = FULL WINDOW ;
//
r o d z a j
o b i e k t u
i n t
o b j e c t = WIRE SPHERE ;
//
r o z m i a r y
b r y ł y
o b c i n a n i a
const GLdouble
l e f t = − 1 0 . 0 ;
const GLdouble
r i g h t = 1 0 . 0 ;
const GLdouble bottom = − 1 0 . 0 ;
const GLdouble
t o p = 1 0 . 0 ;
const GLdouble
n e a r = 5 0 . 0 ;
const GLdouble
f a r = 7 0 . 0 ;
//
w s p ó ł c z y n n i k
s k a l o w a n i a
G L f l o a t
s c a l e = 1 . 0 ;
//
k ą t y
o b r o t u
G L f l o a t
r o t a t e x = 0 . 0 ;
G L f l o a t
r o t a t e y = 0 . 0 ;
//
p r z e s u n i ę c i e
G L f l o a t
t r a n s l a t e x = 0 . 0 ;
G L f l o a t
t r a n s l a t e y = 0 . 0 ;
//
w s k a ź n i k
n a c i ś n i ę c i a
l e w e g o
p r z y c i s k u
m y s z k i
i n t
b u t t o n s t a t e = GLUT UP ;
//
p o ł o ż e n i e
k u r s o r a
m y s z k i
i n t
b u t t o n x , b u t t o n y ;
//
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 ) ;
//
w y b ó r
m a c i e r z y
m o d e l o w a n i a
g l M a t r i x M o d e
(GL MODELVIEW ) ;
//
m a c i e r z
m o d e l 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 r z e s u n i ę c i e
u k ł a d u
w s p ó ł r z ę d n y c h
o b i e k t u
do
ś r o d k a
b r y ł y
o d c i n a n i a
g l T r a n s l a t e f
( 0 , 0 , − ( n e a r+f a r ) / 2 ) ;
//
p r z e s u n i ę c i e
o b i e k t u − r u c h
m y s z k ą
g l T r a n s l a t e f
( t r a n s l a t e x , t r a n s l a t e y , 0 . 0 ) ;
//
s k a l o w a n i e
o b i e k t u − k l a w i s z e
”+”
i
”−”
g l S c a l e f
( s c a l e , s c a l e , s c a l e ) ;
//
o b r o t y
o b i e k t u − k l a w i s z e
k u r s o r a
g l R o t a t e f
( r o t a t e x , 1 . 0 , 0 , 0 ) ;
g l R o t a t e f
( r o t a t e y , 0 , 1 . 0 , 0 ) ;
//
k o l o r
k r a w ę d z i
o b i e k t u
1. Przekształcenia geometryczne
10
g l C o l o r 3 f
( 0 . 0 , 0 . 0 , 0 . 0 ) ;
//
r y s o w a n i e
o b i e k t u
switch
( o b j e c t )
{
//
k u l a
c a s e WIRE SPHERE :
g l u t W i r e S p h e r e
( 1 . 0 , 2 0 , 1 0 ) ;
break ;
//
s t o ż e k
c a s e WIRE CONE :
g l u t W i r e C o n e
( 1 . 0 , 2 . 0 , 2 0 , 1 0 ) ;
break ;
//
s z e ś c i a n
c a s e WIRE CUBE :
g l u t W i r e C u b e
( 1 . 0 ) ;
break ;
//
t o r u s
c a s e WIRE TORUS :
g l u t W i r e T o r u s
( 0 . 2 , 1 , 1 0 , 2 0 ) ;
break ;
//
d w u n a s t o ś c i a n
c a s e WIRE DODECAHEDRON:
g l u t W i r e D o d e c a h e d r o n
( ) ;
break ;
//
c z a j n i k
c a s e WIRE TEAPOT :
g l u t W i r e T e a p o t
( 1 . 0 ) ;
break ;
//
o ś m i o ś c i a n
c a s e WIRE OCTAHEDRON:
g l u t W i r e O c t a h e d r o n
( ) ;
break ;
//
c z w o r o ś c i a n
c a s e WIRE TETRAHEDRON:
g l u t W i r e T e t r a h e d r o n
( ) ;
break ;
//
d w u d z i e s t o ś c i a n
c a s e WIRE ICOSAHEDRON :
g l u t W i r e I c o s a h e d r o n
( ) ;
break ;
}
//
s k i e r o w a n i e
p o l e c e ń
do
w y k o n a n i a
g l F l u s h
( ) ;
//
z a m i a n a
b u f o r ó w
k o l o r u
g l u t S w a p B u f f e r s
( ) ;
}
//
z m i a n a
w i e l k o ś c i
o k n a
void
R esh ape
( i n t
width ,
i n t
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
o k n o
g l V i e w p o r t
( 0 , 0 , width , h e i g h t ) ;
//
w y b ó r
m a c i e r z y
r z u t o w a n i a
g l M a t r i x M o d e
(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
( a s p e c t == ASPECT 1 1 )
{
//
w y s o k o ś ć
o k n a
w i ę k s z a
od
w y s o k o ś c i
o k n a
i f
( w i d t h < h e i g h t && w i d t h > 0 )
g l F r u s t u m
( l e f t , r i g h t , bottom ∗ h e i g h t / width , t o p ∗ h e i g h t / width , n e a r , f a r ) ;
e l s e
//
s z e r o k o ś ć
o k n a
w i ę k s z a
l u b
równa
w y s o k o ś c i
o k n a
1. Przekształcenia geometryczne
11
i f
( w i d t h >= h e i g h t && h e i g h t > 0 )
g l F r u s t u m
( l e f t ∗ w i d t h / h e i g h t , r i g h t ∗ w i d t h / h e i g h t , bottom , top , n e a r , f a r ) ;
}
e l s e
g l F r u s t u m
( l e f t , r i g h t , bottom , top , n e a r , f a r ) ;
//
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 ,
i n t x ,
i n t
y )
{
//
k l a w i s z +
i f
( k e y == ’+ ’ )
s c a l e += 0 . 1 ;
e l s e
//
k l a w i s z −
i f
( k e y == ’− ’ && s c a l e > 0 . 1 )
s c a l e −= 0 . 1 ;
//
o d r y s o w a n i e
o k n a
R esh ape
( g l u t G e t
(GLUT WINDOW WIDTH) , g l u t G e t
(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
S p e c i a l K e y s
( i n t
key ,
i n t x ,
i n t
y )
{
switch
( k e y )
{
//
k u r s o r w l e w o
c a s e GLUT KEY LEFT :
r o t a t e y −= 1 ;
break ;
//
k u r s o r w g ó r ę
c a s e GLUT KEY UP :
r o t a t e x −= 1 ;
break ;
//
k u r s o r w p r a w o
c a s e GLUT KEY RIGHT :
r o t a t e y += 1 ;
break ;
//
k u r s o r w d ó ł
c a s e GLUT KEY DOWN :
r o t a t e x += 1 ;
break ;
}
//
o d r y s o w a n i e
o k n a
R esh ape
( g l u t G e t
(GLUT WINDOW WIDTH) , g l u t G e t
(GLUT WINDOW HEIGHT ) ) ;
}
//
o b s ł u g a
p r z y c i s k ó w
m y s z k i
void MouseButton
( i n t
b u t t o n ,
i n t
s t a t e ,
i n t x ,
i n t
y )
{
i f
( b u t t o n == GLUT LEFT BUTTON)
{
//
z a p a m i ę t a n i e
s t a n u
l e w e g o
p r z y c i s k u
m y s z k i
b u t t o n s t a t e = s t a t e ;
//
z a p a m i ę t a n i e
p o ł o ż e n i a
k u r s o r a
m y s z k i
i f
( s t a t e == GLUT DOWN)
{
b u t t o n x = x ;
b u t t o n y = y ;
}
}
}
//
o b s ł u g a
r u c h u
k u r s o r a
m y s z k i
void MouseMotion
( i n t x ,
i n t
y )
{
1. Przekształcenia geometryczne
12
i f
( b u t t o n s t a t e == GLUT DOWN)
{
t r a n s l a t e x += 1 . 1
∗ ( r i g h t − l e f t ) / g l u t G e t
(GLUT WINDOW WIDTH)
∗ ( x − b u t t o n x ) ;
b u t t o n x = x ;
t r a n s l a t e y += 1 . 1
∗ ( t o p − bottom ) / g l u t G e t
(GLUT WINDOW HEIGHT)
∗ ( b u t t o n y − y ) ;
b u t t o n y = y ;
g l u t P o s t R e d i s p l a y
( ) ;
}
}
//
o b s ł u g a
menu
p o d r ę c z n e g o
void Menu ( i n t
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
o k n o
c a s e FULL WINDOW :
a s p e c t = FULL WINDOW ;
R esha pe
( g l u t G e t
(GLUT WINDOW WIDTH) , g l u t G e t
(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
c a s e ASPECT 1 1 :
a s p e c t = ASPECT 1 1 ;
R esha pe
( g l u t G e t
(GLUT WINDOW WIDTH) , g l u t G e t
(GLUT WINDOW HEIGHT ) ) ;
break ;
//
k u l a
c a s e WIRE SPHERE :
o b j e c t = WIRE SPHERE ;
D i s p l a y
( ) ;
break ;
//
c y l i n d e r
c a s e WIRE CONE :
o b j e c t = WIRE CONE ;
D i s p l a y
( ) ;
break ;
//
s z e ś c i a n
c a s e WIRE CUBE :
o b j e c t = WIRE CUBE ;
D i s p l a y
( ) ;
break ;
//
t o r u s
c a s e WIRE TORUS :
o b j e c t = WIRE TORUS ;
D i s p l a y
( ) ;
break ;
//
d w u n a s t o ś c i a n
c a s e WIRE DODECAHEDRON:
o b j e c t = WIRE DODECAHEDRON;
D i s p l a y
( ) ;
break ;
//
c z a j n i k
c a s e WIRE TEAPOT :
o b j e c t = WIRE TEAPOT ;
D i s p l a y
( ) ;
break ;
//
o ś m i o ś c i a n
c a s e WIRE OCTAHEDRON:
o b j e c t = WIRE OCTAHEDRON;
D i s p l a y
( ) ;
break ;
//
c z w o r o ś c i a n
c a s e WIRE TETRAHEDRON:
o b j e c t = WIRE TETRAHEDRON;
D i s p l a y
( ) ;
break ;
//
d w u d z i e s t o ś c i a n
c a s e WIRE ICOSAHEDRON :
o b j e c t = WIRE ICOSAHEDRON ;
D i s p l a y
( ) ;
1. Przekształcenia geometryczne
13
break ;
//
w y j ś c i e
c a s e EXIT :
e x i t
( 0 ) ;
}
}
i n t
main
( i n t
a r g c ,
char ∗ a r g v [ ] )
{
//
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
(& a r g c , a r g v ) ;
//
i n i c j a l i z a c j a
b u f o r a
r a m k i
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
o k n a
p r o g r a m u
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
o k n a
p r o g r a m u
#i f d e f WIN32
g l u t C r e a t e W i n d o w
( ” P r z e k s z t a ł c e n i a ” ) ;
#e l s e
g l u t C r e a t e W i n d o w
( ” P r z e k s z t a l c e n i a ” ) ;
#e n d i f
//
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
g l u t D i s p l a y F u n c
( D i s p l a y ) ;
//
d o ł ą c z e n i e
f u n k c j i
w y w o ł y w a n e j
p r z y
z m i a n i e
r o z m i a r u
o k n a
g l u t R e s h a p e F u n c
( Re sha pe ) ;
//
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
g l u t K e y b o a r d F u n c
( 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
g l u t S p e c i a l F u n c
( S p e c i a l K e y s ) ;
//
o b s ł u g a
p r z y c i s k ó w
m y s z k i
g l u t M o u s e F u n c
( MouseButton ) ;
//
o b s ł u g a
r u c h u
k u r s o r a
m y s z k i
g l u t M o t i o n F u n c
( MouseMotion ) ;
//
u t w o r z e n i e
podmenu − a s p e k t
o b r a z u
i n t
MenuAspect = g l u t C r e a t e M e n u
( Menu ) ;
#i f d e f WIN32
glutAddMenuEntry
( ” A s p e k t
o b r a z u − c a ł e
okno ” ,FULL WINDOW ) ;
#e l s e
glutAddMenuEntry
( ” A s p e k t
o b r a z u − c a l e
okno ” ,FULL WINDOW ) ;
#e n d i f
glutAddMenuEntry
( ” A s p e k t
o b r a z u
1 : 1 ” , ASPECT 1 1 ) ;
//
u t w o r z e n i e
podmenu − o b i e k t
i n t
MenuObject = g l u t C r e a t e M e n u
( Menu ) ;
glutAddMenuEntry
( ” Kula ” ,WIRE SPHERE ) ;
#i f d e f WIN32
glutAddMenuEntry
( ” S t o ż e k ” ,WIRE CONE ) ;
glutAddMenuEntry
( ” S z e ś c i a n ” ,WIRE CUBE ) ;
glutAddMenuEntry
( ” T o r u s ” ,WIRE TORUS ) ;
glutAddMenuEntry
( ” D w u n a s t o ś c i a n ” ,WIRE DODECAHEDRON ) ;
glutAddMenuEntry
( ” C z a j n i k ” ,WIRE TEAPOT ) ;
glutAddMenuEntry
( ” O ś m i o ś c i a n ” ,WIRE OCTAHEDRON ) ;
glutAddMenuEntry
( ” C z w o r o ś c i a n ” ,WIRE TETRAHEDRON ) ;
glutAddMenuEntry
( ” D w u d z i e s t o ś c i a n ” ,WIRE ICOSAHEDRON ) ;
#e l s e
glutAddMenuEntry
( ” S t o z e k ” ,WIRE CONE ) ;
glutAddMenuEntry
( ” S z e s c i a n ” ,WIRE CUBE ) ;
glutAddMenuEntry
( ” T o r u s ” ,WIRE TORUS ) ;
glutAddMenuEntry
( ” D w u n a s t o s c i a n ” ,WIRE DODECAHEDRON ) ;
glutAddMenuEntry
( ” C z a j n i k ” ,WIRE TEAPOT ) ;
glutAddMenuEntry
( ” O s m i o s c i a n ” ,WIRE OCTAHEDRON ) ;
glutAddMenuEntry
( ” C z w o r o s c i a n ” ,WIRE TETRAHEDRON ) ;
1. Przekształcenia geometryczne
14
glutAddMenuEntry
( ” D w u d z i e s t o s c i a n ” ,WIRE ICOSAHEDRON ) ;
#e n d i f
// menu g ł ó w n e
g l u t C r e a t e M e n u
( Menu ) ;
glutAddSubMenu
( ” A s p e k t
o b r a z u ” , MenuAspect ) ;
glutAddSubMenu
( ” O b i e k t ” , MenuObject ) ;
#i f d e f WIN32
glutAddMenuEntry
( ” W y j ś c i e ” , EXIT ) ;
#e l s e
glutAddMenuEntry
( ” W y j s c i e ” , EXIT ) ;
#e n d i f
//
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 g o
menu
p o d r ę c z n e
g l u t A t t a c h M e n u
(GLUT RIGHT BUTTON ) ;
//
w p r o w a d z e n i e
p r o g r a m u
do
o b s ł u g i
p ę t l i
k o m u n i k a t ó w
g l u t M a i n L o o p
( ) ;
return
0 ;
}
1.7. Stos macierzy modelowania
Do składania przekształceń biblioteka OpenGL wykorzystuje wspomnia-
ny już wcześniej stos macierzy modelowania. W dotychczasowych progra-
mach, oraz pierwszym z przykładowych programów z tego odcinka kursu,
mechanizm stosu nie był faktycznie wykorzystywany. Wszystkie operacje
związane ze stosem macierzy modelowania wykonywane były na macierzy
położonej na szczycie stosu. Pozwala to jednak na efektywną manipulację
jedynie jednym obiektem na scenie. Oczywiście obsługa wielu obiektów tak-
że jest możliwa, ale wymaga to stosowania mniej wygodnych i efektywnych
mechanizmów. W szczególności mogło by się okazać konieczne przechowy-
wanie macierzy modelowania - czyli dublowanie możliwości oferowanej przez
mechanizm stosu.
Po lekturze powyższego wstępu Czytelnik zastanawia się zapewne jak
w praktyce efektywnie można wykorzystać mechanizm stosu macierzy mo-
delowania. Klasycznym przykładem jest budowa obiektów złożonych z wielu
obiektów podstawowych (np. takich jak wyżej opisane obiekty 3D dostępne
w bibliotece GLUT). Drugim, równie często wykorzystywanym przykładem,
jest animacja sceny składającej się z wielu obiektów 3D.
1.7.1. Operacje na stosie
Specyfikacja biblioteki OpenGL przewiduje, że stos macierzy modelo-
wania przechowuje co najmniej 32 macierze. Oczywiście konkretne imple-
mentacje OpenGL mogą dowolnie zwiększać maksymalną pojemność tego
stosu. Opisane poniżej funkcje służą do operacji na każdym rodzaju stosu
dostępnym w OpenGL. Operacja zawsze zostanie wykonana na aktualnie
wybranym rodzaju stosu. Operację odłożenia bieżącej macierzy na stos re-
alizuje funkcja:
1. Przekształcenia geometryczne
15
void glPushMatrix (void)
Natomiast operację zdjęcia macierzy ze stosu wykonuje funkcja:
void glPopMatrix (void)
Próba wykonania niedozwolonej operacji na stosie spowoduje wygenero-
wanie kodu błędu zwracanego przez funkcję glGetError:
— GL STACK UNDERFLOW - próba pobrania elementu z pustego stosu (niedo-
bór stosu),
— GL STACK OVERFLOW - przepełnienie stosu.
Przykładowy program (plik stos modelowania.cpp) opiera się na po-
przednim przykładzie. Podstawową różnicą jest rysowanie jednego obiektu -
piramidy, ale złożonego z dużej ilości elementów podstawowych - sześcianów.
Dla ułatwienia pracy program zawiera dwie funkcje rysujące części piramidy
w postaci bloków 3 × 3 (funkcja Cube3x3) i bloków 2 × 2 (funkcja Cube2x2).
Pierwszy poziom piramidy ma rozmiary 6 × 6 i jest rysowany z czterech
bloków 3 × 3 (funkcja Pyramid). Przed narysowaniem każdego z elemen-
tów pierwszego poziomu macierz modelowania odkładana jest na stos - po
zakończeniu rysowania następuje zdjęcie macierzy ze stosu.
Przy rysowaniu drugiego i trzeciego poziomu piramidy następuje dwu-
krotne odłożenie macierzy modelowania na stos. Po pierwszym przesuwamy
układ współrzędnych od odpowiednią ilość jednostek do góry. Drugie w ko-
lejności odkładanie macierzy na stos wiąże się już bezpośrednio z rysowaniem
kolejnych elementów danego poziomu piramidy.
Rysowanie kolejnych poziomów nie wymaga już dodatkowego opisu - wy-
starcza jednokrotne odłożenie macierzy modelowania na stos. Przykładowy
efekt tych wszystkich przekształceń zawiera rysunek 5.
Oczywiście uzyskanie takiej figury nie wymaga stosowania mechanizmu
stosu macierzy modelowania. Jednak już w tak prostym przykładzie wi-
doczne są korzyści wynikające z takiego rozwiązania. Po pierwsze wszystkie
elementy obiektu 3D, w tym wypadku poziomy piramidy, są od siebie nie-
zależne. Czytelnik może to łatwo sprawdzić odpowiednio modyfikując tekst
źródłowy programu. Trudno nie docenić takiej cechy przy tworzeniu bardziej
skomplikowanych obiektów. Drugą zaletą jest duża przejrzystość rozwiąza-
nia, co ułatwia późniejszą modyfikację programu i usuwanie ewentualnych
błędów. Warto także dodać, że mechanizm stosu jest bardzo szybki i dotyczy
to wszystkich implementacji biblioteki OpenGL, nie tylko sprzętowych.
W programie wykorzystano także kilka innych nieopisanych wcześniej
funkcji biblioteki OpenGL i GLU. W poprzednim przykładzie przy prze-
suwaniu obiektu za pomocą myszki obliczanie wektora przesunięcia opar-
to o dobrane doświadczalnie współczynniki. W przypadku, gdy zmienimy
parametry bryły odcinania te współczynniki trzeba będzie dobierać ponow-
1. Przekształcenia geometryczne
16
Rysunek 5. Program Stos modelowania
nie. Biblioteka GLU zawiera funkcje przeliczające współrzędne w przestrzeni
okna na współrzędne w przestrzeni widoku i odwrotnie.
Przeliczenie współrzędnych w przestrzeni widoku (objx, objy, objz) na
współrzędne w przestrzeni okna (winx, winy, winz) wykonuje funkcja glu-
Project:
GLint gluProject (GLdouble objx,
GLdouble objy,
GLdouble objz,
const GLdouble modelMatrix [16],
const GLdouble projMatrix [16],
const GLint viewport [4],
GLdouble *winx,
GLdouble *winy,
GLdouble *winz)
1. Przekształcenia geometryczne
17
Do przeliczania współrzędnych funkcja gluProject wykorzystuje ma-
cierz modelowania, macierz rzutowania oraz współrzędne okna renderin-
gu, które zawarte są kolejno w parametrach: modelMatrix, projMatrix
i viewport
Przeliczenie współrzędnych w przestrzeni okna (winx, winy, winz) na
współrzędne w przestrzeni widoku (objx, objy, objz) wykonuje funkcja
gluUnProject:
GLint gluUnProject (GLdouble winx,
GLdouble winy,
GLdouble winz,
const GLdouble modelMatrix [16],
const GLdouble projMatrix [16],
const GLint viewport [4],
GLdouble *objx,
GLdouble *objy,
GLdouble *objz)
której parametry mają analogiczne znaczenie jak parametry poprzedniej
funkcji gluProject.
W wersji 1.3 biblioteki GLU dodano funkcję gluUnProject4:
GLint gluUnProject4 (GLdouble winx,
GLdouble winy,
GLdouble winz,
GLdouble clipw,
const GLdouble modelMatrix[16],
const GLdouble projMatrix[16],
const GLint viewport[4],
GLdouble near,
GLdouble far,
GLdouble *objx,
GLdouble *objy,
GLdouble *objz,
GLdouble *objw)
stanowiącą rozszerzenie gluUnProject umożliwiającą obliczenia przy nie-
standardowych ustawieniach bufora głębokości (parametry near i far odpo-
wiadające parametrom funkcji glDepthRange) lub w przypadku, gdy czwar-
ta współrzędna (parametr clipw) przestrzeni okna przyjmuje inną wartość
niż 1. Funkcja zwraca dodatkowo wartość czwartej współrzędnej w przestrze-
ni widoku (parametr objw). Znaczenie tych dodatkowych współrzędnych
poznamy w kolejnych odcinkach kursu.
1. Przekształcenia geometryczne
18
Wartości macierzy modelowania, macierzy rzutowania oraz obszaru ren-
deringu stanowią zmienne stanu maszyny stanu OpenGL. Do odczytu zmien-
nych stanu służy bardzo liczna grupa funkcji glGet, z których najbardziej
uniwersalne są następujące funkcje:
void glGetBooleanv (GLenum pname, GLboolean *params)
void glGetDoublev (GLenum pname, GLdouble *params)
void glGetFloatv (GLenum pname, GLfloat *params)
void glGetIntegerv (GLenum pname, GLint *params)
Parametr pname określa którą wartość maszyny stanów OpenGL chcemy
pobrać (tabela wszystkich możliwych wartości zajmuje 35 stron specyfika-
cji OpenGL 2.1), a params wskaźnik na zwracaną wartość. W zależności
od rodzaju pobieranej wartości params wskazuje na pojedynczą zmienną
lub tablicę. Rodzaj zwracanej (zwracanych) wartości jednoznacznie określa
końcowa część nazwy funkcji.
1.7.2. Plik stos modelowania.cpp
/∗
( c )
J a n u s z
G a n c z a r s k i
h t t p : / / www . j a n u s z g . h g . p l
J a n u s z G @ e n t e r . n e t . p l
∗/
#i n c l u d e <GL/ g l u t . h>
#i n c l u d e < 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
o k n o
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
i n t
a s p e c t = FULL WINDOW ;
//
r o z m i a r y
b r y ł y
o b c i n a n i a
const GLdouble
l e f t = − 1 0 . 0 ;
const GLdouble
r i g h t = 1 0 . 0 ;
const GLdouble bottom = − 1 0 . 0 ;
const GLdouble
t o p = 1 0 . 0 ;
const GLdouble
n e a r = 5 0 . 0 ;
const GLdouble
f a r = 7 0 . 0 ;
//
w s p ó ł c z y n n i k
s k a l o w a n i a
G L f l o a t
s c a l e = 1 . 0 ;
//
k ą t y
o b r o t u
G L f l o a t
r o t a t e x = 0 . 0 ;
G L f l o a t
r o t a t e y = 0 . 0 ;
//
p r z e s u n i ę c i e
G L f l o a t
t r a n s l a t e x = 0 . 0 ;
G L f l o a t
t r a n s l a t e y = 0 . 0 ;
//
w s k a ź n i k
n a c i ś n i ę c i a
l e w e g o
p r z y c i s k u
m y s z k i
1. Przekształcenia geometryczne
19
i n t
b u t t o n s t a t e = GLUT UP ;
//
p o ł o ż e n i e
k u r s o r a
m y s z k i
i n t
b u t t o n x , b u t t o n y ;
//
f u n k c j a
r y s u j ą c a
b l o k
3 x 3
void Cube3x3
( )
{
g l u t W i r e C u b e
( 1 . 0 ) ;
g l T r a n s l a t e f
( 1 . 0 , 0 . 0 , 0 . 0 ) ;
g l u t W i r e C u b e
( 1 . 0 ) ;
g l T r a n s l a t e f
( 0 . 0 , − 1 . 0 , 0 . 0 ) ;
g l u t W i r e C u b e
( 1 . 0 ) ;
g l T r a n s l a t e f
( − 1 . 0 , 0 . 0 , 0 . 0 ) ;
g l u t W i r e C u b e
( 1 . 0 ) ;
g l T r a n s l a t e f
( − 1 . 0 , 0 . 0 , 0 . 0 ) ;
g l u t W i r e C u b e
( 1 . 0 ) ;
g l T r a n s l a t e f
( 0 . 0 , 1 . 0 , 0 . 0 ) ;
g l u t W i r e C u b e
( 1 . 0 ) ;
g l T r a n s l a t e f
( 0 . 0 , 1 . 0 , 0 . 0 ) ;
g l u t W i r e C u b e
( 1 . 0 ) ;
g l T r a n s l a t e f
( 1 . 0 , 0 . 0 , 0 . 0 ) ;
g l u t W i r e C u b e
( 1 . 0 ) ;
g l T r a n s l a t e f
( 1 . 0 , 0 . 0 , 0 . 0 ) ;
g l u t W i r e C u b e
( 1 . 0 ) ;
}
//
f u n k c j a
r y s u j ą c a
b l o k
2 x 2
void Cube2x2
( )
{
g l u t W i r e C u b e
( 1 . 0 ) ;
g l T r a n s l a t e f
( 1 . 0 , 0 . 0 , 0 . 0 ) ;
g l u t W i r e C u b e
( 1 . 0 ) ;
g l T r a n s l a t e f
( 0 . 0 , − 1 . 0 , 0 . 0 ) ;
g l u t W i r e C u b e
( 1 . 0 ) ;
g l T r a n s l a t e f
( − 1 . 0 , 0 . 0 , 0 . 0 ) ;
g l u t W i r e C u b e
( 1 . 0 ) ;
}
//
f u n k c j a
r y s u j ą c a
p i r a m i d ę
z
s z e ś c i a n ó w
void Pyramid
( )
{
//
p o d s t a w a
6 x 6
g l P u s h M a t r i x
( ) ;
g l T r a n s l a t e f
( 1 . 5 , 1 . 5 , 0 . 0 ) ;
Cube3x3
( ) ;
g l P o p M a t r i x
( ) ;
g l P u s h M a t r i x
( ) ;
g l T r a n s l a t e f
( 1 . 5 , − 1 . 5 , 0 . 0 ) ;
Cube3x3
( ) ;
g l P o p M a t r i x
( ) ;
g l P u s h M a t r i x
( ) ;
g l T r a n s l a t e f
( − 1 . 5 , − 1 . 5 , 0 . 0 ) ;
Cube3x3
( ) ;
g l P o p M a t r i x
( ) ;
g l P u s h M a t r i x
( ) ;
g l T r a n s l a t e f
( − 1 . 5 , 1 . 5 , 0 . 0 ) ;
Cube3x3
( ) ;
g l P o p M a t r i x
( ) ;
//
d r u g i
p o z i o m
5 x 5
g l P u s h M a t r i x
( ) ;
g l T r a n s l a t e f
( 0 . 0 , 0 . 0 , 1 . 0 ) ;
g l P u s h M a t r i x
( ) ;
g l T r a n s l a t e f
( 1 . 0 , 1 . 0 , 0 . 0 ) ;
Cube3x3
( ) ;
g l P o p M a t r i x
( ) ;
g l P u s h M a t r i x
( ) ;
g l T r a n s l a t e f
( 1 . 0 , − 1 . 0 , 0 . 0 ) ;
Cube2x2
( ) ;
g l P o p M a t r i x
( ) ;
g l P u s h M a t r i x
( ) ;
g l T r a n s l a t e f
( − 2 . 0 , 2 . 0 , 0 . 0 ) ;
Cube2x2
( ) ;
g l P o p M a t r i x
( ) ;
g l P u s h M a t r i x
( ) ;
1. Przekształcenia geometryczne
20
g l T r a n s l a t e f
( − 1 . 0 , − 1 . 0 , 0 . 0 ) ;
Cube3x3
( ) ;
g l P o p M a t r i x
( ) ;
g l P o p M a t r i x
( ) ;
//
t r z e c i
p o z i o m
4 x 4
g l P u s h M a t r i x
( ) ;
g l T r a n s l a t e f
( 0 . 0 , 0 . 0 , 2 . 0 ) ;
g l P u s h M a t r i x
( ) ;
g l T r a n s l a t e f
( 0 . 5 , − 0 . 5 , 0 . 0 ) ;
Cube2x2
( ) ;
g l P o p M a t r i x
( ) ;
g l P u s h M a t r i x
( ) ;
g l T r a n s l a t e f
( 0 . 5 , 1 . 5 , 0 . 0 ) ;
Cube2x2
( ) ;
g l P o p M a t r i x
( ) ;
g l P u s h M a t r i x
( ) ;
g l T r a n s l a t e f
( − 1 . 5 , 1 . 5 , 0 . 0 ) ;
Cube2x2
( ) ;
g l P o p M a t r i x
( ) ;
g l P u s h M a t r i x
( ) ;
g l T r a n s l a t e f
( − 1 . 5 , − 0 . 5 , 0 . 0 ) ;
Cube2x2
( ) ;
g l P o p M a t r i x
( ) ;
g l P o p M a t r i x
( ) ;
//
c z w a r t y
p o z i o m
3 x 3
g l P u s h M a t r i x
( ) ;
g l T r a n s l a t e f
( 0 . 0 , 0 . 0 , 3 . 0 ) ;
Cube3x3
( ) ;
g l P o p M a t r i x
( ) ;
//
p i ą t y
p o z i o m
2 x 2
g l P u s h M a t r i x
( ) ;
g l T r a n s l a t e f
( 0 . 0 , 0 . 0 , 4 . 0 ) ;
g l T r a n s l a t e f
( − 0 . 5 , 0 . 5 , 0 . 0 ) ;
Cube2x2
( ) ;
g l P o p M a t r i x
( ) ;
//
s z ó s t y
p o z i o m
1 x 1
g l P u s h M a t r i x
( ) ;
g l T r a n s l a t e f
( 0 . 0 , 0 . 0 , 5 . 0 ) ;
g l u t W i r e C u b e
( 1 . 0 ) ;
g l P o p M a t r i x
( ) ;
}
//
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 ) ;
//
w y b ó r
m a c i e r z y
m o d e l o w a n i a
g l M a t r i x M o d e
(GL MODELVIEW ) ;
//
m a c i e r z
m o d e l 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 r z e s u n i ę c i e
u k ł a d u
w s p ó ł r z ę d n y c h
o b i e k t u
do
ś r o d k a
b r y ł y
o d c i n a n i a
g l T r a n s l a t e f
( 0 , 0 , − ( n e a r+f a r ) / 2 ) ;
//
p r z e s u n i ę c i e
o b i e k t u − r u c h
m y s z k ą
g l T r a n s l a t e f
( t r a n s l a t e x , t r a n s l a t e y , 0 . 0 ) ;
//
s k a l o w a n i e
o b i e k t u − k l a w i s z e
”+”
i
”−”
g l S c a l e f
( s c a l e , s c a l e , s c a l e ) ;
//
o b r o t y
o b i e k t u − k l a w i s z e
k u r s o r a
g l R o t a t e f
( r o t a t e x , 1 . 0 , 0 , 0 ) ;
g l R o t a t e f
( r o t a t e y , 0 , 1 . 0 , 0 ) ;
//
k o l o r
k r a w ę d z i
o b i e k t u
g l C o l o r 3 f
( 0 . 0 , 0 . 0 , 0 . 0 ) ;
//
r y s o w a n i e
p i r a m i d y
Pyramid
( ) ;
1. Przekształcenia geometryczne
21
//
s k i e r o w a n i e
p o l e c e ń
do
w y k o n a n i a
g l F l u s h
( ) ;
//
z a m i a n a
b u f o r ó w
k o l o r u
g l u t S w a p B u f f e r s
( ) ;
}
//
z m i a n a
w i e l k o ś c i
o k n a
void
R esh ape
( i n t
width ,
i n t
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
o k n o
g l V i e w p o r t
( 0 , 0 , width , h e i g h t ) ;
//
w y b ó r
m a c i e r z y
r z u t o w a n i a
g l M a t r i x M o d e
(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
( a s p e c t == ASPECT 1 1 )
{
//
w y s o k o ś ć
o k n a
w i ę k s z a
od
w y s o k o ś c i
o k n a
i f
( w i d t h < h e i g h t && w i d t h > 0 )
g l F r u s t u m
( l e f t , r i g h t , bottom ∗ h e i g h t / width , t o p ∗ h e i g h t / width , n e a r , f a r ) ;
e l s e
//
s z e r o k o ś ć
o k n a
w i ę k s z a
l u b
równa
w y s o k o ś c i
o k n a
i f
( w i d t h >= h e i g h t && h e i g h t > 0 )
g l F r u s t u m
( l e f t ∗ w i d t h / h e i g h t , r i g h t ∗ w i d t h / h e i g h t , bottom , top , n e a r , f a r ) ;
}
e l s e
g l F r u s t u m
( l e f t , r i g h t , bottom , top , n e a r , f a r ) ;
//
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 ,
i n t x ,
i n t
y )
{
//
k l a w i s z +
i f
( k e y == ’+ ’ )
s c a l e += 0 . 1 ;
e l s e
//
k l a w i s z −
i f
( k e y == ’− ’ && s c a l e > 0 . 1 )
s c a l e −= 0 . 1 ;
//
o d r y s o w a n i e
o k n a
R esh ape
( g l u t G e t
(GLUT WINDOW WIDTH) , g l u t G e t
(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
S p e c i a l K e y s
( i n t
key ,
i n t x ,
i n t
y )
{
switch
( k e y )
{
//
k u r s o r w l e w o
c a s e GLUT KEY LEFT :
r o t a t e y −= 1 ;
break ;
//
k u r s o r w g ó r ę
c a s e GLUT KEY UP :
r o t a t e x −= 1 ;
break ;
//
k u r s o r w p r a w o
c a s e GLUT KEY RIGHT :
r o t a t e y += 1 ;
break ;
//
k u r s o r w d ó ł
c a s e GLUT KEY DOWN :
1. Przekształcenia geometryczne
22
r o t a t e x += 1 ;
break ;
}
//
o d r y s o w a n i e
o k n a
R esh ape
( g l u t G e t
(GLUT WINDOW WIDTH) , g l u t G e t
(GLUT WINDOW HEIGHT ) ) ;
}
//
o b s ł u g a
p r z y c i s k ó w
m y s z k i
void MouseButton
( i n t
b u t t o n ,
i n t
s t a t e ,
i n t x ,
i n t
y )
{
i f
( b u t t o n == GLUT LEFT BUTTON)
{
//
z a p a m i ę t a n i e
s t a n u
l e w e g o
p r z y c i s k u
m y s z k i
b u t t o n s t a t e = s t a t e ;
//
z a p a m i ę t a n i e
p o ł o ż e n i a
k u r s o r a
m y s z k i
i f
( s t a t e == GLUT DOWN)
{
b u t t o n x = x ;
b u t t o n y = y ;
}
}
}
//
o b s ł u g a
r u c h u
k u r s o r a
m y s z k i
void MouseMotion
( i n t x ,
i n t
y )
{
i f
( b u t t o n s t a t e == GLUT DOWN)
{
//
p o b r a n i e
m a c i e r z
m o d e l o w a n i a
GLdouble model
[ 1 6 ]
;
g l G e t D o u b l e v
(GL MODELVIEW MATRIX, model ) ;
//
p o b r a n i e
m a c i e r z y
r z u t o w a n i a
GLdouble
p r o j
[ 1 6 ]
;
g l G e t D o u b l e v
(GL PROJECTION MATRIX , p r o j ) ;
//
p o b r a n i e
o b s z a r u
r e n d e r i n g u
GLint
v i e w
[ 4 ] ;
g l G e t I n t e g e r v (GL VIEWPORT, v i e w ) ;
//
t a b l i c e
z e
o d c z y t a n y m i
w s p ó ł r z ę d n y m i w
p r z e s t r z e n i
w i d o k u
GLdouble
p r e v
[ 3 ] ,
c u r r
[ 3 ] ;
//
p o b r a n i e
w s p ó ł r z ę d n y c h w
p r z e s t r z e n i
w i d o k u
//
d l a
p o p r z e d n i e g o
p o ł o ż e n i a
k u r s o r a
m y s z k i
g l u U n P r o j e c t
( b u t t o n x , b u t t o n y , 0 . 0 , model , p r o j , view , p r e v +0 , p r e v +1 , p r e v + 2 ) ;
//
p o b r a n i e
w s p ó ł r z ę d n y c h w
p r z e s t r z e n i
w i d o k u
//
d l a
b i e ż ą c e g o
p o ł o ż e n i a
k u r s o r a
m y s z k i
g l u U n P r o j e c t
( x , y , 0 . 0 , model , p r o j , view , c u r r +0 , c u r r +1 , c u r r + 2 ) ;
//
o b l i c z e n i e
w s p ó ł r z ę d n y c h
w e k t o r a
p r z e s u n i ę c i a
o b i e k t u
t r a n s l a t e x += c u r r
[ 0 ] − p r e v
[ 0 ] ;
t r a n s l a t e y += p r e v
[ 1 ] − c u r r
[ 1 ] ;
//
z a p a m i ę t a n i e
p o ł o ż e n i a
k u r s o r a
m y s z k i
b u t t o n x = x ;
b u t t o n y = y ;
//
o d r y s o w a n i e
o k n a
g l u t P o s t R e d i s p l a y
( ) ;
}
}
//
o b s ł u g a
menu
p o d r ę c z n e g o
void Menu ( i n t
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
o k n o
c a s e FULL WINDOW :
a s p e c t = FULL WINDOW ;
R esha pe
( g l u t G e t
(GLUT WINDOW WIDTH) , g l u t G e t
(GLUT WINDOW HEIGHT ) ) ;
break ;
1. Przekształcenia geometryczne
23
//
o b s z a r
r e n d e r i n g u − a s p e k t
1 : 1
c a s e ASPECT 1 1 :
a s p e c t = ASPECT 1 1 ;
R esha pe
( g l u t G e t
(GLUT WINDOW WIDTH) , g l u t G e t
(GLUT WINDOW HEIGHT ) ) ;
break ;
//
w y j ś c i e
c a s e EXIT :
e x i t
( 0 ) ;
}
}
i n t
main
( i n t
a r g c ,
char ∗ a r g v [ ] )
{
//
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
(& a r g c , a r g v ) ;
//
i n i c j a l i z a c j a
b u f o r a
r a m k i
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
o k n a
p r o g r a m u
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
o k n a
p r o g r a m u
g l u t C r e a t e W i n d o w
( ” S t o s
m o d e l o w a n i a ” ) ;
//
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
g l u t D i s p l a y F u n c
( D i s p l a y ) ;
//
d o ł ą c z e n i e
f u n k c j i
w y w o ł y w a n e j
p r z y
z m i a n i e
r o z m i a r u
o k n a
g l u t R e s h a p e F u n c
( Re sha pe ) ;
//
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
g l u t K e y b o a r d F u n c
( 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
g l u t S p e c i a l F u n c
( S p e c i a l K e y s ) ;
//
o b s ł u g a
p r z y c i s k ó w
m y s z k i
g l u t M o u s e F u n c
( MouseButton ) ;
//
o b s ł u g a
r u c h u
k u r s o r a
m y s z k i
g l u t M o t i o n F u n c
( MouseMotion ) ;
//
u t w o r z e n i e
podmenu − a s p e k t
o b r a z u
i n t
MenuAspect = g l u t C r e a t e M e n u
( Menu ) ;
#i f d e f WIN32
glutAddMenuEntry
( ” A s p e k t
o b r a z u − c a ł e
okno ” ,FULL WINDOW ) ;
#e l s e
glutAddMenuEntry
( ” A s p e k t
o b r a z u − c a l e
okno ” ,FULL WINDOW ) ;
#e n d i f
glutAddMenuEntry
( ” A s p e k t
o b r a z u
1 : 1 ” , ASPECT 1 1 ) ;
// menu g ł ó w n e
g l u t C r e a t e M e n u
( Menu ) ;
glutAddSubMenu
( ” A s p e k t
o b r a z u ” , MenuAspect ) ;
#i f d e f WIN32
glutAddMenuEntry
( ” W y j ś c i e ” , EXIT ) ;
#e l s e
glutAddMenuEntry
( ” W y j s c i e ” , EXIT ) ;
#e n d i f
//
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 g o
menu
p o d r ę c z n e
g l u t A t t a c h M e n u
(GLUT RIGHT BUTTON ) ;
//
w p r o w a d z e n i e
p r o g r a m u
do
o b s ł u g i
p ę t l i
k o m u n i k a t ó w
g l u t M a i n L o o p
( ) ;
return
0 ;
}
Literatura
24
Literatura
[1] Mark Segal, Kurt Akeley: The OpenGL Graphics System. A Specification Ver-
sion 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] Richard S. Wright jr, Michael Sweet: OpenGL Księga eksperta Wydanie III,
Helion 2005
[5] The official OpenGL web page,
[6] Piotr Andrzejewski, Jakub Kurzak: Wprowadzenie do OpenGL. Programowanie
zastosowań graficznych, Kwantum 2000
[7] Kevin Hawkins, Dave Astle: OpenGL. Programowanie gier, Helion 2003
[8] Mark J. Kilgard: The OpenGL Utility Toolkit (GLUT) Programming Interface
API Version 3. Silicon Graphics, Inc. 1996