opengl definiowanie sceny 3d


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 . . . . . . . . . . . . . . . . . . . . . . . . 13
1.3.2. Plik szescian3.cpp . . . . . . . . . . . . . . . . . . . . . . . . 16
1.4. Położenie obserwatora . . . . . . . . . . . . . . . . . . . . . . . . . . 19
1.4.1. Plik szescian4.cpp . . . . . . . . . . . . . . . . . . . . . . . . 21
Literatura . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
1. Definiowanie sceny 3D
W kolejnych programach korzystajÄ…cych z biblioteki OpenGL zajmie-
my 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ątko-
wo 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 potrak-
towania. 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 aplika-
cji OpenGL. W naszym drugim programie w trakcie zmiany rozmiaru okna
(funkcjaReshape) będziemy modyfikować obszar renderingu na dwa spo-
soby. Pierwszy polega na objęciu obszarem renderingu całego dostępnego
okna, drugi na takim wyborze okna renderingu aby okno zachowało pier-
wotny aspekt obrazu, czyli stosunek szerokości do wysokości. Oczywiście
przy zastosowaniu pierwszej metody kwadrat będzie zazwyczaj zdeformo-
wany (patrz rysunki 1 i 2). Zmiany sposobu definiowania okna renderin-
gu można dokonać w dowolnym momencie, poprzez wybranie odpowiedniej
opcji w menu podręcznym.
W funkcjiMenuzostała użyta do tej pory nieopisana funkcja z biblioteki
GLUT:
int glutGet (GLenum type)
O tym jakiego rodzaju informacje zwróci funkcjaglutGetdecyduje para-
metrtype. W przykładowym programie są to szerokość i wysokość okna, co
odpowiada parametrom opisanym stałymiGLUTWINDOWWIDTHiGLUTWIN-
DOWHEIGHT.
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 ) 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 . hg . p l
J a nu s zG @ e nter . n e t . p l
"/
#include
#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
i n t Aspe ct = 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 p r y m i t y w u
glEnd ( ) ;
// 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 ( ) ;
// zamiana 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 ( ) ;
}
// zmiana w i e l k o Å› c i okna
void Reshape ( 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 - 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 , g d y 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 ( ) ;
}
// 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 okno
case FULL WINDOW:
Aspect = FULL WINDOW;
Reshape ( 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
case ASPECT 1 1 :
Aspect = ASPECT 1 1 ;
Reshape ( g l u t G e t (GLUT WINDOW WIDTH) , g l u t G e t (GLUT WINDOW HEIGHT ) ) ;
break ;
1. Definiowanie sceny 3D 4
// w y j Å› c i e
case EXIT :
e x i t ( 0 ) ;
}
}
i n t main ( i n t a r gc , 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 (& argc , 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 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
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 okna
glutRe shapeFunc ( 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
#i f d e f WIN32
glutAddMenuEntry (  Obszar r e n d e r i n g u - c a Å‚ e okno  ,FULL WINDOW ) ;
glutAddMenuEntry (  Obszar r e n d e r i n g u - a s p e k t 1 : 1  , ASPECT 1 1 ) ;
glutAddMenuEntry (  W y j Å› c i e  ,EXIT ) ;
#e l s e
glutAddMenuEntry (  Obszar r e n d e r i n g u - c a l e okno  ,FULL WINDOW ) ;
glutAddMenuEntry (  Obszar r e n d e r i n g u - a s p e k t 1 : 1  , ASPECT 1 1 ) ;
glutAddMenuEntry (  W y j s c i e  ,EXIT ) ;
#end if
// 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 k o m un i kat ó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 standar-
dowo dwie metody rzutowania: rzutowanie prostokÄ…tne i rzutowanie perspek-
tywiczne. 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 są rysowane, a obiekty ją przecinające rysowane
są tylko częściowo.
1. Definiowanie sceny 3D 5
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)
której parametry określają współrzędne punktów przecięcia płaszczyzn two-
rzących bryłę odcinania z osiami układu współrzędnych kartezjańskich. Płasz-
czyzny 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łaszczyznie o równaniu z = -near.
Położenie poszczególnych płaszczyzn tworzących bryłę odcinania przedsta-
wia rysunek 3. Trzeba jednak wyraznie 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ąt-
nym
1. Definiowanie sceny 3D 6
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 odpowia-
da wywołaniu funkcjiglOrtho (-1,1,-1,1,-1,1). Oś OZ jest prostopadła
do płaszczyzny obszaru renderingu i przechodzi przez środek tego obsza-
ru. Dlatego rysowany w pierwszym i drugim programie kwadrat zajmował
początkowo czwartą część okna.
FunkcjaglOrthotworzy macierz rzutu prostokÄ…tnego:
ëÅ‚ öÅ‚
right+left
2
0 0
right-left right-left
ìÅ‚ ÷Å‚
top+bottom
2
ìÅ‚ ÷Å‚
0 0
ìÅ‚ top-bottom top-bottom ÷Å‚
ìÅ‚ ÷Å‚
far+near
-2
0 0
íÅ‚ Å‚Å‚
far-near far-near
0 0 0 1
która jest następnie mnożona przez bieżącą macierz i umieszczona na szczy-
cie 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 funk-
cja:
void glMatrixMode (GLenum mode)
gdzie parametrmodemoże przyjąć jedną z wartości:
 GLMODELVIEW- macierz modelowania,
 GLPROJECTION- macierz rzutowania,
 GLTEXTURE- macierz tekstury (omówiona pózniej).
Ponieważ początkowa wartość wybranej macierzy jest nieokreślona, przed
wywołaniemglOrthonależ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 (plikszescian1.cpp) w funkcjiDisplaymacierzy
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 parametryleft,right,bottomitopodpowiadają parametrom funk-
cji glOrtho, a przednia (near) i tylna (far) płaszczyzna obcinania mają
wartości odpowiednio -1 i 1.
1. Definiowanie sceny 3D 7
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
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 wy-
bór, czy scena ma być rysowana z zachowaniem początkowego aspektu ob-
razu 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 ) 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 . hg . p l
J a nu s zG @ e nter . n e t . p l
"/
#include
#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
{
1. Definiowanie sceny 3D 8
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
i n t Aspe ct = 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 m o d e l o w a n i a
glMatrixMode (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 ( ) ;
// 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 ó ł 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 p r y m i t y w u
glEnd ( ) ;
// 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 ( ) ;
// zamiana 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 ( ) ;
}
// zmiana w i e l k o Å› c i okna
1. Definiowanie sceny 3D 9
void Reshape ( 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 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 )
g l O r t h o ( - 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 )
g l O r t h o ( -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
g l O r t h o ( - 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 ( ) ;
}
// 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 okno
case FULL WINDOW:
Aspect = FULL WINDOW;
Reshape ( 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
case ASPECT 1 1 :
Aspect = ASPECT 1 1 ;
Reshape ( 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
case EXIT :
e x i t ( 0 ) ;
}
}
i n t main ( i n t a r gc , 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 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
#i f d e f WIN32
glutCreateWindow (  S z e Å› c i a n 1  ) ;
#e l s e
glutCreateWindow (  S z e s c i a n 1  ) ;
#end if
// 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 okna
glutR eshape Func ( Reshape ) ;
// u t w o r z e n i e menu p o d r Ä™ c z n e g o
glutCreateMenu ( Menu ) ;
1. Definiowanie sceny 3D 10
// 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
#i f d e f WIN32
glutAddMenuEntry (  Aspekt o br azu - c a Å‚ e okno  ,FULL WINDOW ) ;
glutAddMenuEntry (  Aspekt o br azu 1 : 1  , ASPECT 1 1 ) ;
glutAddMenuEntry (  W y j Å› c i e  ,EXIT ) ;
#e l s e
glutAddMenuEntry (  Aspekt o br azu - c a l e okno  ,FULL WINDOW ) ;
glutAddMenuEntry (  Aspekt o br azu 1 : 1  , ASPECT 1 1 ) ;
glutAddMenuEntry (  W y j s c i e  ,EXIT ) ;
#end if
// 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 k o m u n ika tó w
glutMainLoop ( ) ;
return 0 ;
}
1.3. Rzutowanie perspektywiczne
Rzutowanie perspektywiczne daje bardziej realistyczne efekty niż rzuto-
wanie 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)
Parametryleft,right,bottomitopwyznaczają rozmiary górnej pod-
stawy bryły odcinania (jest to obszar bezpośrednio odwzorowywany na ob-
szar renderingu), anearifarwyznaczają 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.
Parametrynearifarmuszą mieć wartości dodatnie.
Macierz rzutowania perspektywicznego, tworzona przez funkcjęglFrus-
tumi mnożona przez aktualnie wybraną macierz, ma postać:
ëÅ‚ öÅ‚
right+left
2near
0 0
right-left right-left
ìÅ‚ ÷Å‚
top+bottom
2near
ìÅ‚ ÷Å‚
0 0
ìÅ‚ top-bottom top-bottom ÷Å‚
ìÅ‚ ÷Å‚
far+near 2far·near
0 0
íÅ‚ Å‚Å‚
far-near far-near
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ównearifar:
far
r =
near
1. Definiowanie sceny 3D 11
Y
top
-far
left
right
-near
bottom
X
Z
Rysunek 5. Położenie płaszczyzn bryły odcinania w rzutowaniu perspekty-
wicznym
Im większa wartość r, tym mniej efektywne jest działanie z-bufora. Oczy-
wiścienearnigdy 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 funk-
cja z biblioteki GLU:
void gluPerspective (GLdouble fovy,
GLdouble aspect,
GLdouble zNear,
GLdouble zFar)
gdzie parametr fovy określa w stopniach kąt widzenia obserwatora zawar-
ty w płaszczyznie YZ ( (top, 0, bottom)), aaspectjest stosunkiem szero-
kości do wysokości przedniej płaszczyzny odcinania, czyli górnej podstawy
ostrosłupa ograniczającego scenę 3D. ParametryzNearizFarodpowiadają
parametromnearifarfunkcjiglFrustum.
1. Definiowanie sceny 3D 12
Macierz rzutowania perspektywicznego, tworzona przez funkcjęgluPer-
spectivei mnożona przez aktualnie wybraną macierz, ma postać:
ëÅ‚ öÅ‚
f ovy
ctg
2
0 0 0
aspect
ìÅ‚ ÷Å‚
ìÅ‚ fovy ÷Å‚
0 ctg 0 0
ìÅ‚ ÷Å‚
2
ìÅ‚ ÷Å‚
zF ar+zNear 2·zF ar·zNear
íÅ‚ Å‚Å‚
0 0
zNear-zF ar zNear-zF ar
0 0 -1 0
Wewnętrznie funkcjagluPerspectivewykorzystuje do ustawienia ma-
cierzy rzutowania perspektywicznego funkcjęglFrustum. Oto wzory prze-
kształcenia parametrów funkcjigluPerspectivena parametryglFrustum:

fovy
left = -aspect · zNear · tg Ä„
360

fovy
right = aspect · zNear · tg Ä„
360
fovy
bottom = -zNear · tg Ä„
360

fovy
top = zNear · tg Ä„
360
W kolejnym przykładowym programie (plikszescian2.cpp) do utworze-
nia macierzy rzutowania perspektywicznego wykorzystamy funkcjęglFrus-
tum. 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 funkcjaglFrustum.
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 spo-
soby 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 zmienio-
nej 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 funkcjaglTranslatef, która wywoływana jest bezpośred-
nio po zainicjowaniu macierzy modelowania macierzÄ… jednostkowÄ… (patrz
funkcjaDisplay). W efekcie otrzymamy sześcian przedstawiony na rysun-
ku 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 trans-
formowane do docelowego położenia w scenie 3D. Funkcje umożliwiające
1. Definiowanie sceny 3D 13
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.
Rysunek 6. Początkowe okno programu Sześcian 2
1.3.1. Plik szescian2.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 . hg . p l
J a nu s zG @ e nter . n e t . p l
"/
#include
#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
i n t Aspe ct = 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 ( )
1. Definiowanie sceny 3D 14
{
// 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 m o d e l o w a n i a
glMatrixMode (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 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 p r y m i t y w u
glEnd ( ) ;
// 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 ( ) ;
// zamiana 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 ( ) ;
}
// zmiana w i e l k o Å› c i okna
void Reshape ( 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 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
1. Definiowanie sceny 3D 15
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 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 okno
case FULL WINDOW:
Aspect = FULL WINDOW;
Reshape ( 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
case ASPECT 1 1 :
Aspect = ASPECT 1 1 ;
Reshape ( 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
case EXIT :
e x i t ( 0 ) ;
}
}
i n t main ( i n t a r gc , 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 (& argc , 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 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
#i f d e f WIN32
glutCreateWindow (  S z e Å› c i a n 2  ) ;
#e l s e
glutCreateWindow (  S z e Å› c i a n 2  ) ;
#end if
// 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 okna
glutRe shapeFunc ( 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
#i f d e f WIN32
glutAddMenuEntry (  Aspekt ob r a z u - c a Å‚ e okno  ,FULL WINDOW) ;
glutAddMenuEntry (  Aspekt ob r a z u 1 : 1  , ASPECT 1 1 ) ;
glutAddMenuEntry (  W y j Å› c i e  ,EXIT ) ;
1. Definiowanie sceny 3D 16
#e l s e
glutAddMenuEntry (  Aspekt ob r a z u - c a l e okno  ,FULL WINDOW) ;
glutAddMenuEntry (  Aspekt ob r a z u 1 : 1  , ASPECT 1 1 ) ;
glutAddMenuEntry (  W y j s c i e  ,EXIT ) ;
#end if
// 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 k o m un i kat ów
glutMainLoop ( ) ;
return 0 ;
}
Drugi program przedstawiajÄ…cy rzutowanie perspektywiczne (plikszes-
cian3.cpp) stosuje funkcjęgluPerspective. Aby jednak nie powielać roz-
wiązań z poprzedniego programu dodamy mechanizm pokazujący jaki wpływ
na wygląd obiektów 3D ma zmiana położenie środka perspektywy, realizo-
wana poprzez zmianÄ™ kÄ…ta widzenia obserwatora (parametrfovyfunkcji
gluPerspective). W tym celu potrzebna jest obsługa klawiatury. Podsta-
wowa 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 klawia-
tury.
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ć%.
1.3.2. Plik szescian3.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 . hg . p l
J a nu s zG @ e nter . n e t . p l
"/
#include
#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
} ;
// p i o n o w y 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 ( )
{
1. Definiowanie sceny 3D 17
Rysunek 7. Początkowe okno programu Sześcian 3
// 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 m o d e l o w a n i a
glMatrixMode (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 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 ) ;
1. Definiowanie sceny 3D 18
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 p r y m i t y w u
glEnd ( ) ;
// 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 ( ) ;
// zamiana 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 ( ) ;
}
// zmiana w i e l k o Å› c i okna
void Reshape ( 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 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
// p r z y p a d k u , g d y w y s o k o ś ć o b r a z u w y n o s i 0
GLdouble a s p e c t = 1 ;
i f ( h e i g h t > 0 )
a s p e c t = width / ( GLdouble ) h e i g h t ;
// 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 , i n t x , i n t y )
{
// k l a w i s z +
i f ( key ==  +  && f o v y < 1 8 0 )
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 ( 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 menu p o d r Ä™ c z n e g o
void Menu ( i n t v a l u e )
{
1. Definiowanie sceny 3D 19
switch ( v a l u e )
{
// w y j Å› c i e
case EXIT :
e x i t ( 0 ) ;
}
}
i n t main ( i n t a r gc , 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 (& argc , 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 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
#i f d e f WIN32
glutCreateWindow (  S z e Å› c i a n 3  ) ;
#e l s e
glutCreateWindow (  S z e s c i a n 3  ) ;
#end if
// 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 okna
glutRe shapeFunc ( 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
#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 ) ;
#end if
// 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 k o m un i kat ó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 po-
czą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 po-
krywa 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ła-
1. Definiowanie sceny 3D 20
twić 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 funkcjigluLookAtoznaczają:
 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 (plikszescian4.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 cie-
kawy efekt obserwacji sceny z pewnej odległości.
Zmiana położenia obserwatora realizowana jest w funkcjachKeyboard
(przyciski  + i  - ) orazSpecialKeys(klawisze kursora). Warto zauważyć,
że zmiany współrzędnych obserwatora, które reprezentują zmienneeyex,
eyeyieyez, są odwrotne niż można by się spodziewać. Przykładowo na-
ciśnięcie strzałki w dół powoduje zwiększenie o 0,1 zmiennejeyey, która
określa współrzędną Y położenia obserwatora. Jest to spowodowane tym,
że macierz modelowania, modyfikowana przy wywołaniu funkcjigluLookAt,
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 obiek-
tu jest przesunięciem o wektor [1, 0, 0], dla obserwatora jest przesunięciem
o wektor przeciwny tj. [-1, 0, 0]. Dobre poznanie opisanego mechanizmy wy-
maga 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 (funkcjaKeyboard).
Funkcja obsługująca klawisze kursora oraz przyciski funkcyjne (w przykła-
dowym programie jest to funkcjaSpecialKeys) ma trzy parametry:
 key- kod przycisku; zwracana jest jedna z poniższych wartości:
 GLUTKEYF1- przycisk F1,
 GLUTKEYF2- przycisk F2,
 GLUTKEYF3- przycisk F3,
1. Definiowanie sceny 3D 21
 GLUTKEYF4- przycisk F4,
 GLUTKEYF5- przycisk F5,
 GLUTKEYF6- przycisk F6,
 GLUTKEYF7- przycisk F7,
 GLUTKEYF8- przycisk F8,
 GLUTKEYF9- przycisk F9,
 GLUTKEYF10- przycisk F10,
 GLUTKEYF11- przycisk F11,
 GLUTKEYF12- przycisk F12,
 GLUTKEYLEFT- kursor w lewo,
 GLUTKEYUP- kursor do góry,
 GLUTKEYRIGHT- kursor w prawo,
 GLUTKEYDOWN- kursor w dół,
 GLUTKEYPAGEUP- przycisk Page Up
 GLUTKEYPAGEDOWN- przycisk Page Down,
 GLUTKEYHOME- przycisk Home,
 GLUTKEYEND- przycisk End,
 GLUTKEYINSERT- przycisk Insert.
 x,y- współrzędne kursora myszki w chwili naciśnięcia przycisku klawia-
tury.
Podobnie jak w przypadku poprzedniej funkcji obsługującej klawiaturę,
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 zródłowy znajduje się poniżej.
1.4.1. Plik szescian4.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 . hg . p l
J a nu s zG @ e nter . n e t . p l
"/
#include
#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
i n t Aspe ct = 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
1. Definiowanie sceny 3D 22
Rysunek 8. Przykładowe okno programu Sześcian 4
GLdouble eyex = 0 ;
GLdouble eyey = 0 ;
GLdouble e y e z = 3 ;
// w s p ó ł r z ę d n e p u n k t u w k t ó r e g o k i e r u n k u j e s t z w r ó c o n y o b s e r w a t o r ,
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 m o d e l o w a n i a
glMatrixMode (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 ( ) ;
// 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 ) ;
1. Definiowanie sceny 3D 23
// 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 p r y m i t y w u
glEnd ( ) ;
// 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 ( ) ;
// zamiana 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 ( ) ;
}
// zmiana w i e l k o Å› c i okna
void Reshape ( 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 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
1. Definiowanie sceny 3D 24
void Keyboard ( unsigned char key , i n t x , i n t 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 ( 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 ( 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 ;
break ;
}
// o d r y s o w a n i e okna
Reshape ( 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 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 okno
case FULL WINDOW:
Aspect = FULL WINDOW;
Reshape ( 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
case ASPECT 1 1 :
Aspect = ASPECT 1 1 ;
Reshape ( 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
case EXIT :
e x i t ( 0 ) ;
}
}
i n t main ( i n t a r gc , 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 (& argc , 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 okna programu
1. Definiowanie sceny 3D 25
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
#i f d e f WIN32
glutCreateWindow (  S z e Å› c i a n 4  ) ;
#e l s e
glutCreateWindow (  S z e s c i a n 4  ) ;
#end if
// 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 okna
glutRe shapeFunc ( 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
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 ) ;
// 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
#i f d e f WIN32
glutAddMenuEntry (  Aspekt ob r a z u - c a Å‚ e okno  ,FULL WINDOW) ;
glutAddMenuEntry (  Aspekt ob r a z u 1 : 1  , ASPECT 1 1 ) ;
glutAddMenuEntry (  W y j Å› c i e  ,EXIT ) ;
#e l s e
glutAddMenuEntry (  Aspekt ob r a z u - c a l e okno  ,FULL WINDOW) ;
glutAddMenuEntry (  Aspekt ob r a z u 1 : 1  , ASPECT 1 1 ) ;
glutAddMenuEntry (  W y j s c i e  ,EXIT ) ;
#end if
// 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 k o m un i kat ów
glutMainLoop ( ) ;
return 0 ;
}
Literatura 26
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] Richard S. Wright jr, Michael Sweet: OpenGL Księga eksperta Wydanie III,
Helion 2005
[5] The official OpenGL web page,http://www.opengl.org
[6] Piotr Andrzejewski, Jakub Kurzak: Wprowadzenie do OpenGL. Programowa-
nie 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


Wyszukiwarka