Janusz Ganczarski
OpenGL
Kolory i cieniowanie
Spis treści
Spis treści . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1
. . . . . . . . . . . . . . . . . . . . . . . . . . . .
1
Bufor koloru . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1
. . . . . . . . . . . . . . . . . . . . . . . .
1
Funkcje z grupy glColor3 . . . . . . . . . . . . . . . . . . . .
2
Funkcje z grupy glColor4 . . . . . . . . . . . . . . . . . . . .
3
Kolor - tryb indeksowy . . . . . . . . . . . . . . . . . . . . . . . . .
3
Cieniowanie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4
Dithering . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4
Program przykładowy . . . . . . . . . . . . . . . . . . . . . . . . . .
5
Plik trojkat.cpp . . . . . . . . . . . . . . . . . . . . . . . . .
7
Literatura . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
11
1. Kolory i cieniowanie
Standardowo biblioteka OpenGL korzysta z modelu barw RGB, który
wykorzystuje trzy barwy podstawowe: czerwoną (R), zieloną (G) i niebie-
ską (B). Jak wspomnieliśmy na początku kursu barwa może być określona
bezpośrednio poprzez wartości składowych bądź w trybie indeksowym z uży-
ciem mapy (tablicy) barw. Tryb indeksowy zostanie opisany, ale przykładowe
programy nie będą go stosowały. Przedtem jednak poznamy budowę bufora
koloru - najważniejszego elementu bufora ramki obrazu.
1.1. Bufor koloru
Bufor koloru służy do przechowywania obrazu renderowanej sceny 3D.
Jest on podzielony na kilka buforów. Typowo OpenGL stosuje dwa bufory
koloru: przedni i tylny. Bieżąca scena znajduje się w przednim buforze i jest
wyświetlana na ekranie monitora, a jednocześnie w tylnym buforze rysowana
jest kolejna ramka sceny. Po zakończeniu rysowania, bufory są zamieniane
i cały proces zaczyna się od początku. Podwójne buforowanie eliminuje mi-
gotanie obrazu występujące przy stosowaniu pojedynczego bufora koloru.
Niektóre implementacje biblioteki OpenGL udostępniają stereoskopowy
tryb działania bufora koloru, tj. generowanie dwóch niezależnych obrazów
dla prawego i lewego oka. Oba kanały stereoskopowe mają własne niezależne
bufory przednie i tylne. Ponadto implementacja OpenGL może posiadać
dodatkowe (pomocnicze) bufory koloru.
Wybór trybu działania bufora kolorów dokonywany jest na początku
działania programu. W przypadku biblioteki GLUT realizuje to opisywana
już funkcja glutInitDisplayMode, której parametrem jest maska bitowa.
Stała GLUT SINGLE wybiera domyślny w bibliotece GLUT tryb pojedynczego
bufora koloru. Podwójne buforowanie wymaga stałej GLUT DOUBLE. Z kolei
tryb stereoskopowy uruchamia stała GLUT STEREO.
Inna grupa stałych odpowiada, za wybór sposobu zapisu kolorów w bufo-
rach koloru: GLUT RGB lub GLUT RGBA - bezpośredni tryb RGB wyświetlania
kolorów (bez kanału alfa), GLUT INDEX - tryb indeksowy z mapą kolorów,
GLUT ALPHA - obsługa kanału alfa, GLUT LUMINANCE - alternatywny tryb
wyświetlania obrazu w odcieniach szarości, w którym składowe R pikseli
stanowią indeksy do mapy kolorów początkowo zawierającej liniowo upo-
rządkowane odcienie szarości.
1.2. Kolor - tryb bezpośredni
W trybie bezpośrednim kolor ustalany jest przy użyciu funkcji z grupy
glColor. Funkcje te można podzielić na trzy grupy. Pierwsza to funkcje
trójargumentowe, przyjmujące składowe RGB w różnych formatach; druga
1. Kolory i cieniowanie
2
grupa to funkcje czteroargumentowe umożliwiające określenie także wartości
składowej alfa (RGBA); trzecia to funkcje przyjmujące wskaźnik na tablicę
ze składowymi RGB lub RGBA. W przypadku, gdy kolor określają trzy
składowe wartość składowej alfa wynosi 1.0. Początkową wartość bieżącego
koloru określają składowe RGBA: (1, 1, 1, 1).
Funkcje przyjmujące argumenty zmiennoprzecinkowe wymagają wartości
z przedziału [0, 1], gdzie 0 określa minimalną wartość składowej koloru, a 1
maksymalną wartość składowej. Wartości przekraczające ten przedział są
odpowiednio przycinane. Funkcje przyjmujące argumenty całkowitoliczbowe
przekształcają te wartości do liczb zmiennoprzecinkowych z przedziału [0, 1]
wg schematu przedstawionego w tabeli 1, gdzie c oznacza składową koloru.
typ OpenGL
konwersja
GLubyte
c
2
8
−1
GLbyte
2c+1
2
8
−1
GLushort
c
2
16
−1
GLshort
2c+1
2
16
−1
GLuint
c
2
32
−1
GLint
2c+1
2
32
−1
Tabela 1: Konwersja składowych koloru w OpenGL
1.2.1. Funkcje z grupy glColor3
void glColor3b (GLbyte red, GLbyte green, GLbyte blue)
void glColor3d (GLdouble red, GLdouble green, GLdouble blue)
void glColor3f (GLfloat red, GLfloat green, GLfloat blue)
void glColor3i (GLint red, GLint green, GLint blue)
void glColor3s (GLshort red, GLshort green, GLshort blue)
void glColor3ub (GLubyte red, GLubyte green, GLubyte blue)
void glColor3ui (GLuint red, GLuint green, GLuint blue)
void glColor3us (GLushort red, GLushort green, GLushort blue)
void glColor3bv(const GLbyte *v)
void glColor3dv(const GLdouble *v)
void glColor3fv(const GLfloat *v)
void glColor3iv(const GLint *v)
void glColor3sv(const GLshort *v)
void glColor3ubv(const GLubyte *v)
void glColor3uiv(const GLuint *v)
void glColor3usv(const GLushort *v)
1. Kolory i cieniowanie
3
1.2.2. Funkcje z grupy glColor4
void glColor4b (GLbyte red, GLbyte green, GLbyte blue,
GLbyte alpha)
void glColor4d (GLdouble red, GLdouble green, GLdouble blue,
GLdouble alpha)
void glColor4f (GLfloat red, GLfloat green, GLfloat blue,
GLfloat alpha)
void glColor4i (GLint red, GLint green, GLint blue,
GLint alpha)
void glColor4s (GLshort red, GLshort green, GLshort blue,
GLshort alpha)
void glColor4ub (GLubyte red, GLubyte green, GLubyte blue,
GLubyte alpha)
void glColor4ui (GLuint red, GLuint green, GLuint blue,
GLuint alpha)
void glColor4us (GLushort red, GLushort green, GLushort blue,
GLushort alpha)
void glColor4bv(const GLbyte *v)
void glColor4dv(const GLdouble *v)
void glColor4fv(const GLfloat *v)
void glColor4iv(const GLint *v)
void glColor4sv(const GLshort *v)
void glColor4ubv(const GLubyte *v)
void glColor4uiv(const GLuint *v)
void glColor4usv(const GLushort *v)
1.3. Kolor - tryb indeksowy
W trybie indeksowym kolor określany jest pojedynczą liczbą - indeksem
do mapy (tablicy) kolorów, która zawiera informacje o składowych RGB.
Typowo wielkość mapy kolorów wynosi od 256 (2
8
) do 4.096 (2
12
). Zarzą-
dzanie mapą kolorów jest uzależnione od konkretnego systemu okienkowego,
w którym pracuje program. Biblioteka OpenGL nie posiada żadnych mecha-
nizmów pozwalających na zmianę zawartości mapy kolorów oraz zmiany jej
rozmiarów.
Wybór indeksu bieżącego koloru realizują funkcje z grupy glIndex:
void glIndexd (GLdouble c)
void glIndexf (GLfloat c)
void glIndexi (GLint c)
void glIndexs (GLshort c)
1. Kolory i cieniowanie
4
void glIndexdv (const GLdouble *c)
void glIndexfv (const GLfloat *c)
void glIndexiv (const GLint *c)
void glIndexsv (const GLshort *c)
Początkowa wartość indeksu bieżącego koloru wynosi 1.
Czyszczenie bufora koloru w trybie indeksowym wykonuje funkcja:
void glClearIndex (GLfloat c)
gdzie parametr c określa indeks mapy kolorów. Domyślna wartość indeksu
wynosi 0. Jest to odpowiednik funkcji glClearColor działającej w trybie
bezpośrednim.
1.4. Cieniowanie
Cieniowaniem nazywamy metodę ustalania koloru poszczególnych pikse-
li wielokąta. Biblioteka OpenGL udostępnia standardowo dwa modele cie-
niowania: cieniowanie płaskie oraz cieniowanie gładkie. W cieniowaniu pła-
skim wielokąt otrzymuje jeden kolor - określony dla ostatniego wierzchołka
(wyjątek stanowi prymityw GL POLYGON, o kolorze którego decyduje kolor
określony dla pierwszego wierzchołka). Cieniowanie gładkie wykorzystuje
algorytm Gourauda, który w uproszczeniu polega na liniowej interpolacji
wartości składowych koloru określonych dla każdego wierzchołka wielokąta.
Cieniowane gładkie daje zadowalające efekty przy stosunkowo niewielkich
wymaganiach obliczeniowych.
Wybór rodzaju cieniowania umożliwia funkcja:
void glShadeModel (GLenum mode)
której parametr mode przyjmuje jedną z wartości:
— GL FLAT - cieniowanie płaskie,
— GL SMOOTH - cieniowanie gładkie.
Domyślnie stosowane jest cieniowanie gładkie.
1.5. Dithering
Wewnętrznie biblioteka OpenGL opisuje kolory za pomocą liczb zmien-
noprzecinkowych. Natomiast końcowy efekt widoczny na ekranie monitora
zależy od możliwości systemu okienkowego oraz karty graficznej. W sytu-
acji, gdy w systemie dostępna jest niewielka ilość barw (np. 256), biblioteka
OpenGL może symulować kolory metodą ditheringu. W uproszczeniu al-
gorytm ten umieszcza w pobliżu siebie różnokolorowe plamki (piksele) tak
aby sprawiały wrażenie jednolitej barwy. Technika ta bywa określana także
mianem rozpraszania, rozsiewania lub roztrząsania.
1. Kolory i cieniowanie
5
Włączenie i wyłączenie ditheringu wymaga odpowiedniego użycia funkcji
glEnable/glDisable z parametrem GL DITHER. Domyślnie dithering jest
wyłączony.
1.6. Program przykładowy
Przykładowy program (plik trojkat.cpp) to nieco uproszczona wer-
sja klasycznego programu wykorzystującego bibliotekę OpenGL. Początko-
wo barwa każdego z wierzchołków odpowiada maksymalnej wartości każdej
z trzech składowych modelu RGB (patrz rysunek 1).
Rysunek 1. Program Trójkąt - widok początkowy
Program umożliwia zmianę kolorów wierzchołków trójkąta. Służą do te-
go przyciski r, g, b (zmniejszanie wartości składowych RGB) oraz R, G, B
(zwiększanie wartości składowych RGB). Ponadto z poziomu menu podręcz-
nego użytkownik może wybrać rodzaj cieniowania oraz włączyć i wyłączyć
1. Kolory i cieniowanie
6
dithering. Na dole okna program wyświetla m.in. ilość bitów przypadającą
na każdą składową RGBA. Wykorzystano do tego funkcję glGetIntegerv
z pierwszym parametrem o wartości: GL RED BITS, GL GREEN BITS, GL BLUE -
BITS i GL ALPHA BITS.
Po uruchomieniu programu w trybie 256 kolorowym Czytelnik ma moż-
liwość sprawdzenia zarówno efektów działania algorytmu ditheringu (rysu-
nek 2) jak też i działania cieniowania gładkiego przy ograniczonej ilości
barw (rysunek 3). Oba rysunki powstały w systemie Windows XP w trybie
zgodności 256 kolorów. Ocenę jakości tak generowanej grafiki pozostawiamy
Czytelnikowi.
Rysunek 2. Program Trójkąt w trybie 256 kolorowym z ditheringiem
1. Kolory i cieniowanie
7
Rysunek 3. Program Trójkąt w trybie 256 kolorowym bez ditheringu
1.6.1. Plik trojkat.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 r i n g . h>
#i n c l u d e < s t d l i b . h>
#i n c l u d e < s t d i o . h>
//
s t a ł e
do
o b s ł u g i
menu
p o d r ę c z n e g o
enum
{
FLAT SHADING ,
//
c i e n i o w a n i e
p ł a s k i e
SMOOTH SHADING,
//
c i e n i o w a n i e
g ł a d k i e
( Gourauda )
DITHERING ,
//
d i t h e r i n g
EXIT
//
w y j ś c i e
} ;
//
m o d e l
c i e n i o w a n i a
GLenum s h a d i n g m o d e l = GL SMOOTH ;
1. Kolory i cieniowanie
8
//
d i t h e r i n g
GLboolean
d i t h e r i n g = GL FALSE ;
//
w a r t o ś c i
s k ł a d o w y c h
b a r w
G L f l o a t
r e d = 1 . 0 ,
g r e e n = 1 . 0 ,
b l u e = 1 . 0 ;
//
f u n k c j a
r y s u j ą c a
n a p i s w wybranym
m i e j s c u
void
D r a w S t r i n g
( G L f l o a t
x ,
G L f l o a t
y ,
char ∗ s t r i n g )
{
//
p o ł o ż e n i e
n a p i s u
g l R a s t e r P o s 2 f
( x , y ) ;
//
w y ś w i e t l e n i e
n a p i s u
i n t
l e n = s t r l e n
( s t r i n g ) ;
f o r
( i n t
i = 0 ;
i < l e n ;
i ++)
g l u t B i t m a p C h a r a c t e r
( GLUT BITMAP 9 BY 15 , s t r i n g
[ i ] ) ;
}
//
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
( ) ;
//
w ł ą c z e n i e
d i t h e r i n g u
i f
( d i t h e r i n g == GL TRUE)
g l E n a b l e
( GL DITHER ) ;
//
w y b ó r
m o d e l u
c i e n i o w a n i a
g l S h a d e M o d e l
( s h a d i n g m o d e l ) ;
//
r y s o w a n i e
t r ó j k ą t a
g l B e g i n
(GL TRIANGLES ) ;
// ” c z e r w o n y ”
w i e r z c h o ł e k
g l C o l o r 3 f
( r e d , 0 . 0 , 0 . 0 ) ;
g l V e r t e x 2 f
( 0 . 1 , 0 . 1 ) ;
// ” z i e l o n y ”
w i e r z c h o ł e k
g l C o l o r 3 f
( 0 . 0 , g r e e n , 0 . 0 ) ;
g l V e r t e x 2 f
( 0 . 9 , 0 . 3 ) ;
// ” n i e b i e s k i ”
w i e r z c h o ł e k
g l C o l o r 3 f
( 0 . 0 , 0 . 0 , b l u e ) ;
g l V e r t e x 2 f
( 0 . 3 , 0 . 9 ) ;
g l E n d
( ) ;
//
w y ś w i e t l e n i e
p a r a m e t r ó w
r e n d e r i n g u
char
s t r i n g
[ 1 0 0 ] ;
g l C o l o r 3 f
( 0 . 0 , 0 . 0 , 0 . 0 ) ;
//
i l o ś c
b i t ó w
na
p o s z c z e g ó l n e
s k ł a d o w e RGBA
GLint
r , b , g , a ;
g l G e t I n t e g e r v
( GL RED BITS,& r ) ;
g l G e t I n t e g e r v
( GL GREEN BITS,& g ) ;
g l G e t I n t e g e r v
( GL BLUE BITS,&b ) ;
g l G e t I n t e g e r v
( GL ALPHA BITS,& a ) ;
s p r i n t f
( s t r i n g , ”BITS : R=%i G=%i B=%i A=%i ” , r , g , b , a ) ;
D r a w S t r i n g
( 0 , 0 . 0 1 , s t r i n g ) ;
//
d i t h e r i n g
w ł ą c z o n y / w y ł ą c z o n y
i f
( g l I s E n a b l e d
( GL DITHER ) == GL TRUE)
s t r c p y
( s t r i n g , ”GL DITHER :
t r u e ” ) ;
e l s e
s t r c p y
( s t r i n g , ”GL DITHER :
f a l s e ” ) ;
D r a w S t r i n g
( 0 , 0 . 0 5 , s t r i n g ) ;
1. Kolory i cieniowanie
9
//
w y ł ą c z e n i e
d i t h e r i n g u
g l D i s a b l e
( GL DITHER ) ;
//
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
( ) ;
//
r z u t o w a n i e
p r o s t o k ą t n e
g l u O r t h o 2 D
( 0 , 1 , 0 , 1 ) ;
//
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 )
{
//
z m i a n a
w a r t o ś c i
s k ł a d o w e j R
i f
( k e y == ’R ’ && r e d < 1 . 0 )
r e d += 0 . 0 5 ;
e l s e
i f
( k e y == ’ r ’ && r e d > 0 . 0 )
r e d −= 0 . 0 5 ;
//
z m i a n a
w a r t o ś c i
s k ł a d o w e j G
i f
( k e y == ’G ’ && g r e e n < 1 . 0 )
g r e e n += 0 . 0 5 ;
e l s e
i f
( k e y == ’ g ’ && g r e e n > 0 . 0 )
g r e e n −= 0 . 0 5 ;
//
z m i a n a
w a r t o ś c i
s k ł a d o w e j B
i f
( k e y == ’B ’ && b l u e < 1 . 0 )
b l u e += 0 . 0 5 ;
e l s e
i f
( k e y == ’ b ’ && b l u e > 0 . 0 )
b l u e −= 0 . 0 5 ;
//
n a r y s o w a n i e
s c e n y
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 )
{
//
c i e n i o w a n i e
p ł a s k i e
c a s e FLAT SHADING :
s h a d i n g m o d e l = GL FLAT ;
D i s p l a y
( ) ;
break ;
//
c i e n i o w a n i e
g ł a d k i e
( Gourauda )
c a s e SMOOTH SHADING :
s h a d i n g m o d e l = GL SMOOTH ;
D i s p l a y
( ) ;
break ;
//
d i t h e r i n g
c a s e DITHERING :
1. Kolory i cieniowanie
10
d i t h e r i n g = ! d i t h e r i n g ;
D i s p l a y
( ) ;
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
( 5 0 0 , 5 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
( ” T r ó j k ą t ” ) ;
#e l s e
g l u t C r e a t e W i n d o w
( ” T r o j k a t ” ) ;
#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 ) ;
//
u t w o r z n e i e
podmenu − M o d e l
c i e n i o w a n i a
i n t
S h a d i n g M o d e l = g l u t C r e a t e M e n u
( Menu ) ;
#i f d e f WIN32
glutAddMenuEntry
( ” C i e n i o w a n i e
p l a s k i e ” ,FLAT SHADING ) ;
glutAddMenuEntry
( ” C i e n i o w a n i e
g l a d k i e
( Gourauda ) ” ,SMOOTH SHADING ) ;
#e l s e
#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
( ” Model
c i e n i o w a n i a ” , S h a d i n g M o d e l ) ;
#i f d e f WIN32
glutAddMenuEntry
( ” D i t h e r i n g :
w ł ą c z / w y ł ą c z ” ,DITHERING ) ;
glutAddMenuEntry
( ” W y j ś c i e ” , EXIT ) ;
#e l s e
glutAddMenuEntry
( ” D i t h e r i n g :
w l a c z / w y l a c z ” ,DITHERING ) ;
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
11
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,
[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