background image

OpenGL 3.2 

Wprowadzenie 

Janusz Ganczarski 

www.januszg.hg.pl

 

 

 

background image

Wstęp 

 

W  tym  odcinku  kursu  poznamy  niezbędne  wiadomości  wstępne  dotyczące  historii  oraz 

podstaw  budowy  i  działania  biblioteki  OpenGL.  Czytelnik  znajdzie  tutaj  także  uzasadnienie  do 
konwencji przyjętej w dalszej części kursu. 

Historia OpenGL 

 

Specyfikacja  pierwszej  wersji  biblioteki  OpenGL  (ang.  Open  Graphics  Library)  została 

opublikowana  1  czerwca  1992  roku  na  bazie  języka  GL  opracowanego  przez  firmę  Silicon  Graphics 
Inc.  (SGI)  na  potrzeby  stacji  graficznych  IRIS.  Początkiem  sukcesu  OpenGL  stała  się  jednak  dopiero 
wersja 1.1, opublikowana 4 marca 1997 roku, którą zaimplementowano m.in. w systemach z rodziny 
Microsoft  Windows.  Kolejne  wersje  biblioteki  (1.2,  1.3,  1.4,  1.5,  2.0,  2.1,  3.0  i  najnowsza  3.1  z  24 
marca 2009  roku)  są  znakomitą  ilustracją  rozwoju  sprzętu  graficznego  i  tendencji  w  programowym 
generowaniu grafiki. 
 

Przez  tych  kilkadziesiąt  lat  jedną  z  głównych  idei  twórców  OpenGL  była  zgodnośd  wstecz 

biblioteki.  W  praktyce  programy  przygotowane  dla  wcześniejszych  wersji  biblioteki  działały 
prawidłowo  także  na  jej  najnowszych  implementacjach.  Drugą  zasadą  OpenGL  jest  jej 
wieloplatformowośd – programy z niej korzystające działają praktycznie na wszystkich współczesnych 
systemach  operacyjnych.  Cechy  te  są  miarą  sukcesu  OpenGL,  która  jest  obecnie  podstawową 
niskopoziomową  biblioteką  graficzną  3D,  standardem  powszechnie  wykorzystywanym  przez 
producentów oprogramowania użytkowego i gier. 
 

Od początku rozwojem OpenGL zajmowała się ARB (ang. Architecture Review Board), w skład 

której  wchodzili  przedstawiciele  najważniejszych  firm  z  branży  komputerowej.  Taki  sposób 
wprowadzania zmian w  bibliotece  zapewnia  OpenGL zachowanie  niezależności od jednej  platformy 
sprzętowej lub programowej przy jednoczesnym uwzględnieniu najnowszych osiągnięd w dziedzinie 
grafiki komputerowej. Oczywiście współpraca wielu firm, o często sprzecznych interesach, nie zawsze 
przebiegała  idealnie.  Producenci  sprzętu  graficznego  promowali  własne  rozwiązania, 
niekompatybilne  z  rozwiązaniami  konkurencji,  a  spory  wewnątrz  ARB  powodowały  opóźnienia  w 
przygotowywaniu nowych wersji specyfikacji. 
 

Od 2006 roku rolę opiekuna OpenGL przejął Khronos Group, który rozwija także inne otwarte 

standardy  programistyczne.  Początkowo  krytykowany  za  opóźnienia,  Khronos  Group  w  drugiej 
połowie 2008 roku wprowadził specyfikację wersji 3.0 i krótko po tym opublikowane zostały kolejne 
wersje  OpenGL  oznaczone  numerami  3.1  i  3.2.  Ewolucję  OpenGL  zaproponowaną  przez  Khronos 
Group  opiszemy  nieco  dalej,  z  kilkuletniej  perspektywy  wydaje  się  jednak,  że  zmiana  ta  wywarła 
pozytywny wpływ na tempo i kierunek rozwoju biblioteki. 

Rozszerzenia 

 

Jednym  z  najczęściej  dyskutowanych  mechanizmów  OpenGL  są  rozszerzenia.  Rozszerzenia 

określają  dodatkowe  możliwości  implementacji  biblioteki  i  mogą  dotyczyd  najróżnorodniejszych  jej 
elementów.  Zaletą  tego  mechanizmu  jest  dostępnośd  z  poziomu  OpenGL  najnowszych  możliwości 
sprzętu graficznego, ale jest jednocześnie to także wada. Rozszerzenia proponowane przez niektóre 
firmy  nie  były  implementowane  przez  inne  (czasami  wynikało  to  jednak  z  braku  możliwości 
technicznych),  co  czyniło  rozszerzenia  mechanizmem  niepewnym  w  zastosowaniach  komercyjnych. 
Mimo tych wad rozszerzenia na trwałe wpisały się w bibliotekę OpenGL i stanowią ważny mechanizm 
wspomagający jej rozwój. 

OpenGL 3.0 - rewolucja przez ewolucję 

 

Wspomniana  wcześniej  wersja  3.0  biblioteki  OpenGL  zapoczątkowała  zupełnie  nowe 

podejście  do  dotychczas  obowiązujących  zasad.  Twórcy  standardu  zauważyli  bowiem,  że  dalsze 
utrzymywanie  tak  rozbudowanej  i  w  znacznej  części  przestarzałej  funkcjonalności  nie  znajduje 
praktycznego  uzasadnienie.  Wyodrębniono  liczną  grupę  tzw.  funkcji  przestarzałych,  która  została 
wytypowana  do  usunięcia  w  przyszłych  wersjach  specyfikacji.  Wskazuje  to  na  generalną  tendencję 

background image

ewolucji  OpenGL  –  stopniowe  usuwanie  przestarzałych  jej  elementów  i  zastępowanie  ich 
nowoczesnymi programowalnymi mechanizmami. 
 

Kolejną  nowością  w  bibliotece  OpenGL  3.0  jest  wymuszenie  na  twórcach  systemów 

okienkowych  utworzenia  funkcji  obsługujących  nowy  kontekst  renderingu.  Związane  jest  to  z 
zupełnie  nową  w  bibliotece  OpenGL  koncepcją  profilowania  kontekstów  renderingu  oraz 
planowanym cyklem usuwania z biblioteki przestarzałych mechanizmów. W przyszłości planowane są 
profile  przeznaczone  do  rozrywki,  tworzenia  dokumentów  i  stron  WWW,  obsługi  aplikacji 
desktopowych,  czy  też  dedykowane  do  urządzeo  mobilnych.  Warto  zauważyd,  że  ARB  zastrzegła 
sobie  wyłącznośd  do  tworzenia  profili  OpenGL.  Sposób  obsługi  nowego  kontekstu  renderingu  musi 
umożliwiad aplikacji wskazanie konkretnego profilu niezbędnego do działania programu. Zauważmy, 
że brak nowego kontekstu renderingu przy redukcji funkcjonalności OpenGL, mógłby doprowadzid w 
przyszłości do błędów przy uruchamianiu starszych programów. 
 

Początkowo  wersja  3.0  OpenGL  spotkała  się  z  dośd  chłodnym  przyjęciem  ze  strony 

środowiska  programistycznego.  Wśród  głównych  zarzutów  pojawiały  się  tezy  o  braku  pełnej 
rezygnacji  z  przestarzałych  funkcji  oraz  braku  modelu  obiektowego.  Wszystko  to  było  związane  z 
oczekiwaniami  na  zupełnie  nowe  API  biblioteki.  Całkiem  słusznie  niezadowolenie  wzbudzało  także 
wielomiesięczne opóźnienie w prezentacji specyfikacji biblioteki. 
 

Analiza  decyzji  Khronos  Group  wskazuje  jednak,  że  podjęto  bardzo  racjonalne  decyzje.  Na 

obecnym  etapie  rozwoju  biblioteki  nie  była  możliwa  rezygnacja  z  całej  jej  dotychczasowej 
funkcjonalności.  Zbyt  dużo  jest  bowiem  na  rynku  oprogramowania  z  tego  korzystającego  –  w  grę 
wchodzą chodby niezwykle skomplikowane aplikacje inżynierskie i naukowe. Wprowadzenie nowego 
kontekstu  renderingu,  mechanizmu  profili  oraz  redukcji  funkcjonalności  ułatwi  stopniowe 
przechodzenie do przyszłych wersji biblioteki. 

OpenGL 3.1 – dalszy etap rewolucji przez ewolucję 

 

Kolejna odsłona biblioteki OpenGL pojawiła się bardzo szybko (oczywiście w porównaniu do 

poprzednich standardów w tym zakresie) i stanowi kolejny istotny krok w jej rozwoju. Zdecydowano 
się  na  usunięcie  wszystkich  funkcji  określonych  w  wersji  3.0  jako  przestarzałe,  chod  pozostawiono 
jeszcze  dodatkową  furtkę  w  postaci  rozszerzenia  GL_ARB_compatibility,  które  zawiera  wszystkie 
usunięte  funkcje.  Dzięki  temu  API  stał  się  znacznie  mniejsze,  co  widad  chodby  po  objętości 
specyfikacji. Pełna  jej wersja obejmująca opis funkcji przestarzałych  to blisko 500 stron, a właściwa 
zajmuje nieco ponad 350 stron. 
 

Usunięcie  przestarzałej  funkcjonalności  znaczne  uprościło  bibliotekę  i  jednocześnie  ułatwiło 

jej stosowanie. Jednak z ułatwieo tych w pełni skorzystają jedynie twórcy nowych aplikacji, którzy od 
początku zdecydują się korzystanie wyłącznie z nowoczesnych rozwiązao oferowanych przez OpenGL 
3.0/3.1. 

OpenGL 3.2 – szybka ewolucja 

 

OpenGL  3.2  to  kolejny  etap  rewolucji  przez  ewolucję.  Specyfikacja  została  opublikowana 

nieco  ponad  cztery  miesiące  po  upublicznieniu  wersji  3.1  i  wnosi  szereg  nowych  możliwości  do 
biblioteki,  w  tym  .  Jedną  z  bardziej  praktycznych  zmian  jest  zdefiniowanie  dwóch  profili: 
podstawowego,  obejmującego  tylko  nieusuniętą  funkcjonalnośd  i  kompatybilnego,  zgodnego  ze 
wszystkim  poprzednimi  wersjami  OpenGL.  Nie  zmieniono  przy  tym  praktycznie  funkcjonalności 
określonych  jako  przestarzałe,  co  wskazuje  na  pewną  stabilizację  w  dalszym  kierunku  rozwoju 
biblioteki. 
 

OpenGL  w  wersji  3.2  bez  rozszerzeo  można  w  pełni  porównywad  z  aktualnym  jej 

odpowiednikiem,  tj.  biblioteką  DirectX  10.0,  a  wraz  z  zaaprobowanymi  przez  ARB  rozszerzeniami: 
GL_ARB_draw_buffers_blend, 

GL_ARB_sample_shading, 

GL_ARB_texture_cube_map_array, 

GL_ARB_texture_gather i GL_ARB_texture_query_lod z biblioteką DirectX w wersji 10.1. 

background image

GLSL 

 

Język  programów  cieniowania  OpenGL  GLSL  (ang.  OpenGL  Shading  Language),  zwanymi 

najczęściej  shaderami,  został  wprowadzony  w  wersji  2.0  biblioteki,  a  od  wersji  3.1  stanowi 
podstawowy  element  potoku  renderingu  zarówno  na  etapie  przetwarzania  wierzchołków  jaki 
fragmentów. Sam język GLSL sukcesywnie ewoluował wraz z kolejnymi wersjami OpenGL. Aktualnie 
jego najnowszą wersją jest 1.50, która odpowiada możliwościom tzw. Shader Model 4.1 języka HLSL z 
biblioteki DirectX 10.1. Dodajmy jeszcze, że wersja 3.1 OpenGL obsługuje shadery GLSL w wersji 1.30 i 
1.40, a wersja 3.2 shadery w wersji 1.40 i 1.50. 
 

Język  GLSL  jest  opisany  w  odrębnej  specyfikacji,  która  tworzy  spójną  całośd  ze  specyfikacją 

podstawowego API biblioteki OpenGL. 

Powiązania z systemami okienkowymi 

 

Biblioteka  OpenGL  wymaga  wsparcia  API  systemu  okienkowego  do  tworzenia  i  zarządzania 

kontekstami  graficznymi,  renderingu  w  oknie  oraz  obsługi  innych  zasobów.  Wszystkie  liczące  się 
współczesne  systemy  operacyjne  posiadają  API  obsługujące  bibliotekę  OpenGL.  W  systemie  X 
Window,  dostępnym  głownie  pod  Unix  i  Linux,  jest  to  GLX.  Warto  także  wspomnied,  że 
implementacje  GLX  istnieją  również  w  systemach  Microsoft  Windows,  MacOS  X  i  kilku  innych 
platformach,  na  których  jest  dostępny  X  Serwer.  OpenGL  w  systemach  Microsoft  Windows 
obsługiwany jest przez WGL. Quartz, warstwa graficzna systemu MacOS X, zawiera kilka interfejsów 
API obsługujących OpenGL. Są to CGL, AGL i NSGLView. 
 

Oczywiście stosowanie rozwiązao specyficznych dla danego systemu operacyjnego powoduje, 

że  danego  programu  nie  można  skompilowad  i  uruchomid  w  innym  systemie  operacyjnym  bez 
dokonania  szeregu  zmian  w  kodzie  źródłowym.  Rozwiązanie  tego  problemu  stanowią  biblioteki 
oferujące  jeden,  niezależny  od  systemu  operacyjnego,  interfejs  do  obsługi  okien  i  komunikatów. 
Pierwszą  biblioteką  tego  typu  była  biblioteka  AUX  (ang.  Auxiliary  Library),  jednak  bodaj  największą 
popularnośd zdobyła biblioteka GLUT (ang. OpenGL Utility Toolkit), opracowana i rozwijana w latach 
1994-1998 przez Marka J. Kilgarda. Pomimo sędziwego wieku jest ona ciągle powszechnie stosowana. 

Typy danych 

 

Typy danych w obsługiwane przez bibliotekę OpenGL przedstawia Tabela 1. Specyfikacja nie 

określa jakiego rodzaju typy danych są użyte w konkretnej implementacji, zawiera jedynie minimalne 
wymagania  związane  z  precyzją  i  wykonywaniem  operacji  na  całkowitych  i  zmiennoprzecinkowych 
typach  danych. W  szczególności implementacja może używad  typów  danych o większej ilości bitów 
niż minimalne wskazane we wspomnianej wyżej tabeli. Typy GLintptr, GLsizeiptr i GLsync 
mają  ilośd  bitów  opisaną  jako  prtbits,  co  oznacza  minimalną  ilośd  bitów  niezbędną  w  danej 
implementacji  do  umieszczenia  wskaźnika.  Typy  te  muszą  umożliwid  zapamiętanie  dowolnego 
adresu.  Trzeba  także  wyraźnie  podkreślid,  że  typy  danych  OpenGL  nie  są  typami  danych 
występującymi w języku C (pomimo częściowej zgodności nazw). Tak więc, na przykład, typ GLint 
niekoniecznie  jest  równoznaczny  z  typem  int  w  C.  Ponadto,  poza  wymienionymi  typami  funkcje 
OpenGL korzystają z typu pustego GLvoid. 
 

Typ GL 

Minimalna ilość 
bitów 

Opis 

GLboolean 

typ logiczny 

GLbyte 

liczba całkowita ze znakiem w kodzie uzupełnieo do 2 

GLubyte 

liczba całkowita bez znaku 

GLchar 

znaki tworzące ciągi 

GLshort 

16 

liczba całkowita ze znakiem w kodzie uzupełnieo do 2 

GLushort 

16 

liczba całkowita bez znaku 

GLint 

32 

liczba całkowita ze znakiem w kodzie uzupełnieo do 2 

background image

GLuint 

32 

liczba całkowita bez znaku 

GLint64 

64 

liczba całkowita ze znakiem w kodzie uzupełnieo do 2 

GLuint64 

64 

liczba całkowita bez znaku 

GLsizei 

32 

nieujemna liczba całkowita 

GLenum 

32 

typ wyliczeniowy 

GLintptr 

ptrbits 

liczba całkowita ze znakiem w kodzie uzupełnieo do 2 

GLsizeiptr 

ptrbits 

nieujemna liczba całkowita 

GLsync 

ptrbits 

uchwyt obiektu synchronizacji 

GLbitfield 

32 

pole bitowe 

GLhalf 

16 

liczba zmiennoprzecinkowa połówkowej precyzji zakodowana 
jako skalar bez znaku 

GLfloat 

32 

liczba zmiennoprzecinkowa 

GLclampf 

32 

liczba zmiennoprzecinkowa ograniczona do przedziału        

GLdouble 

64 

liczba zmiennoprzecinkowa podwójnej precyzji 

GLclampd 

64 

liczba zmiennoprzecinkowa podwójnej precyzji ograniczona 
do przedziału        

Tabela 1 Typy danych w bibliotece OpenGL 

Składnia poleceń 

 

Polecenia  OpenGL  są  funkcjami  lub  procedurami.  Różne  grupy  poleceo  wykonują  tę  samą 

operację,  lecz  różnią  się  sposobem  w  jaki  dostarczane  są  do  nich  argumenty.  Ogólnie  rzecz  biorąc, 
deklaracja polecenia posiada formę: 
 
rtype Name{1|2|3|4}{b|s|i|i64|f|d|ub|us|ui}{v}( [args ,] T arg1, … , 
                                                T argN [, args] ); 
 
 

Polecenia OpenGL są zbudowane z nazwy, po której następuje, w zależności od konkretnego 

przypadku,  maksymalnie  do  4  znaków.  rtype  jest  typem  zwracanym  przez  funkcję.  Nawiasy  {} 
dołączają szereg znaków (lub zestawów znaków), z których tylko jeden jest używany. Pierwszy znak 
{1|2|3|4}  oznacza  liczbę  wartości  wskazanego  typu,  które  muszą  byd  przedstawione  do 
polecenia.  Drugi  znak  lub  zestaw  znaków  {b|s|i|i64|f|d|ub|us|ui}  wskazuje  konkretne 
rodzaje  argumentów:  8-bitowe  liczby  całkowite,  16-bitowe  liczby  całkowite,  32-bitowe  liczby 
całkowite,  64-bitowe  liczby  całkowite,  liczby  zmiennoprzecinkowe  pojedynczej  precyzji  lub  liczby 
zmiennoprzecinkowe podwójnej precyzji – patrz Tabela 2. Zauważmy, że wskazując na typ bez znaku 
dodajemy  literę  u  na  początku  tego  nazwy  typu  (na  przykład  unsigned  byte  jest  skracany  do 
ubyte).  Ostatni  znak  {v},  jeśli  jest  obecny,  wskazuje,  że  polecenie  zawiera  wskaźnik  do  tablicy 
(wektora) wartości, a nie serię poszczególnych argumentów. 
 

Litera  Odpowiadający typ GL 

GLbyte 

GLshort 

GLint 

i64 

GLint64 

GLfloat 

GLdouble 

ub  GLubyte 
us  GLushort 
ui  GLuint 

Tabela 2 Powiązanie sufiksów poleceo GL z typami argumentów. Patrz Tabela 1 z definicjami typów GL 

background image

 

Argumenty poleceo umieszczone w nawiasach [args ,] i [, args] mogą, ale nie muszą 

byd obecne. N argumentów od arg1 do argN ma typ T, który odpowiada jednemu ze znaków lub 
parze znaków wskazanych w Tabela 2. Jeśli ostatnim znakiem nie jest v, to N jest podane przez znaki 

{1|2|3|4}

  (jeśli  ich  nie  ma,  to  liczba  argumentów  jest  ustalona).  Jeśli  ostatnim  znakiem  jest  v,  to 

tylko  arg1  jest  obecny  i  jest  to  tablica  N  wartości  wskazanego  typu.  Argumenty,  których  typ  jest 
stały  (tzn.  nie  wskazany  przez  sufiks  polecenia)  są  jednym  z  typów  danych  OpenGL  zawartych  w 
Tabela 1 lub wskaźnikami do jednego z tych typów. 
 

Przykładowo grupa funkcji glUniform* w specyfikacji OpenGL jest opisywana następująco: 

 
void Uniform{1234}{if}( int location, T value ); 
 
co wskazuje osiem deklaracji funkcji, przedstawionych poniżej w notacji ANSI C: 
 
void Uniform1i( int location, int value ); 
void Uniform1f( int location, float value ); 
void Uniform2i( int location, int v0, int v1 ); 
void Uniform2f( int location, float v0, float v1 ); 
void Uniform3i( int location, int v0, int v1, int v2 ); 
void Uniform3f( int location, float v0, float v2, float v2 ); 
void Uniform4i( int location, int v0, int v1, int v2, int v3 ); 
void Uniform4f( int location, float v0, float v1, float v2, 
                float v3 ); 
 
 

W  dalszej  części  kursu  będziemy  używad  pełnych  deklaracji  funkcji  w  języku  ANSI  C,  jednak 

prezentacja  zasad budowy  poleceo OpenGL ułatwi  Czytelnikowi samodzielne  zgłębianie specyfikacji 
biblioteki. 

Zmienne stanu 

 

Zmienne  stanu  (ang.  state)  są  ważnym  wewnętrznym  elementem  OpenGL  opisującym 

ustawienia biblioteki. Wiele  zmiennych stanu jest  dwustanowych, inne mają wartości całkowite lub 
zmiennoprzecinkowe.  Wszystkie  zmienne  stanu  tworzą  tzw.  maszynę  stanów  (ang.  state  machine), 
która steruje zachowaniem OpenGL. 
 

Wyróżniamy  dwa  rodzaje  zmiennych  stanu.  Pierwszy  typ,  zwany  zmiennymi  serwera  GL, 

znajduje się w serwerze GL. Większośd zmiennych stanu GL wchodzi w skład tej kategorii. Drugi typ, 
zwany  zmiennymi  klienta  GL,  znajduje  się  w  kliencie  GL.  W  typowym  przypadku  klientem  jest 
aplikacja wykorzystująca polecenia OpenGL, a serwerem aktualnie używana implementacja biblioteki 
(np. w sterowniku karty graficznej). Każdy egzemplarz kontekstu OpenGL zawiera jeden pełny zestaw 
zmiennych  stanu  serwera  GL.  Natomiast  każde  połączenie  od  klienta  do  serwera  zawiera  odrębny 
zbiór zmiennych stanu zarówno klienta jak i serwera OpenGL. 
 

Zmienne stanu modyfikowane są, w sposób jawny lub nie, przez polecenia biblioteki OpenGL, 

które będziemy poznawad w dalszych odcinkach kursu. Natomiast do odczytu zmiennych stanu służy 
bardzo liczna grupa funkcji glGet*, z których najbardziej podstawowe są następujące funkcje: 
 
void glGetBooleanv( GLenum pname, GLboolean *params ); 
void glGetIntegerv( GLenum pname, GLint *params ); 
void glGetInteger64v( GLenum pname, GLint64 *params ); 
void glGetFloatv( GLenum pname, GLfloat *params ); 
void glGetDoublev( GLenum pname, GLdouble *params ); 
 
 

Parametr pname określa, którą wartośd maszyny stanów OpenGL chcemy pobrad (wszystkie 

zmienne  stanu  przedstawiamy  w  odrębnym  odcinku  kursu),  a  params  wskaźnik  na  zwracaną 

background image

wartośd.  W  zależności  od  rodzaju  pobieranej  zmiennej  tablica  params  może  zawierad  pojedynczą 
zmienną  lub  tablicę  zmiennych.  Program  musi  zapewnid  odpowiednią  ilośd  miejsca  w  pamięci. 
Zauważmy, że rodzaj zwracanej lub zwracanych wartości jednoznacznie określa koocowa częśd nazwy 
funkcji. 

Obsługa błędów 

 

Biblioteka  OpenGL  zawiera  mechanizmy  obsługi  błędów.  Jednak  z  założenia  wykrywanych 

jest tylko częśd sytuacji spośród zbioru warunków, które mogłyby byd uważane za błędy. Stanowi to 
kompromis  na  rzecz  efektywności,  ponieważ  w  wielu  przypadkach  kontrola  błędów  miałby 
niekorzystny wpływ na wydajnośd programu wolnego od błędów. 
 

Informację o kodzie bieżącego błędu zwraca funkcja: 

 
GLenum glGetError( void ); 
 
 

Zestawienie  zwracanych  kodów  błędów  zawiera  Tabela  3.  Działanie  OpenGL  jest 

niezdefiniowane  tylko  w  przypadku  wystąpienia  błędu  o  kodzie  GL_OUT_OF_MEMORY.  W 
pozostałych  przypadkach  błąd  nie  powoduje  przerwania  wykonywania  programu,  nie  jest 
wykonywana  jedynie  funkcja  odpowiedzialna  za  jego  powstanie.  Polecenie  takie  na  ma  wpływu  na 
stan OpenGL lub zawartośd bufora ramki. Jeśli polecenie generujące błąd zwraca wartości, zwracana 
jest wartośd zero. Jeśli polecenie generujące błąd zmienia wartości poprzez wskaźnik do argumentu, 
nie są dokonywane zmiany tych wartości. 
 

Kod błędu 

Opis 

Czy błędne polecenie 
jest ignorowane? 

GL_INVALID_ENUM 

Argument GLenum 
poza zakresem 

Tak 

GL_INVALID_VALUE 

Argument liczbowy 
poza zakresem 

Tak 

GL_INVALID_OPERATION 

Nielegalna operacja w 
bieżącym stanie 

Tak 

GL_INVALID_FRAMEBUFFER_OPERATION  Niekompletny obiekt 

bufora ramki 

Tak 

GL_OUT_OF_MEMORY 

Brak pamięci do 
wykonania polecenia 

Nieokreślone 

GL_NO_ERROR 

Brak błędu 

Tabela 3 Zestawienie kodów błędów OpenGL 

 

Kiedy  błąd  zostanie  wykryty,  ustawiana  jest  flaga  błędu  i  rejestrowany  jest  jego  kod.  Jeżeli 

występują kolejne  błędy  nie wpływają one  na ten  zarejestrowany kod.  Dopiero, gdy wywołana jest 
funkcja glGetError, zwracany jest kod błędu i czyszczona jest flaga, tak aby kolejny błąd mógł byd 
zarejestrowany.  Jeżeli  glGetError  zwraca  GL_NO_ERROR  oznacza  to,  że  od  ostatniego 
wywołania  glGetError  (lub  od  kiedy  GL  został  zainicjowany)  nie  był  wykryty  żaden  błąd. 
Implementacja  może  przechowywad  więcej  niż  jedną  informację  o  błędzie.  W  takim  przypadku 
wywołanie glGetError zwraca kody kolejnych zarejestrowanych błędów, tak długo aż nie zostanie 
zwrócona wartośd GL_NO_ERROR. 
 

Typowy kod odczytujący błędy zgłaszane przez bibliotekę OpenGL ma postad poniższej pętli: 

 
GLenum error; 
while( ( error = glGetError() ) != GL_NO_ERROR ) 

    // obsługa błędu 

background image


 
 

Ogólne warunki generowania błędów przedstawione są poniżej: 

 

Jeśli  polecenie  wymagające  wartości  wyliczeniowej  określonej  jako  stała  symboliczna 
otrzymuje wartośd, która nie należy do dopuszczalnych dla tego polecenia, generowany jest 
błąd GL_INVALID_ENUM. 

 

Jeśli  przekazywana  jest  ujemna  liczba,  a  typ  argumentu  jest  określony  jako  GLsizei  lub 
GLsizeiptr, zostanie wygenerowany błąd GL_INVALID_VALUE. 

 

Jeśli  ubocznym  efektem  wykonania  polecenia  jest  wyczerpanie  pamięci,  może  byd 
wygenerowany błąd GL_OUT_OF_MEMORY. 

W  innych  wypadkach,  błędy  generowane  są  tylko  na  warunkach,  które  są  wyraźnie  opisane  w 
specyfikacji biblioteki OpenGL. 

Operacje OpenGL i potok renderingu 

 

OpenGL  koncentruje  się  jedynie  na  renderingu  do  bufora  ramki  oraz  czytaniu  wartości 

zapisanych  w  tym  buforze.  Biblioteka  nie  ma  wsparcia  dla  innych  urządzeo,  takich  jak  myszy  i 
klawiatury,  stąd  trzeba    używad  innych  mechanizmów  w  celu  przetworzenia  informacji 
wprowadzanych przez użytkownika. 
 

Rysunek 1 przedstawia schemat działania OpenGL. Z lewej strony diagramu wprowadzane są 

polecenia  OpenGL. Niektóre  z nich  określają obiekty geometryczne, które mają zostad  narysowane, 
inne kontrolują obsługę obiektów przez różne etapy renderingu. Polecenia zawsze są przetwarzane w 
kolejności,  w  jakiej  zostały  przekazane  do  OpenGL,  a  ewentualne  opóźnienie  realizacji  skutków 
danego polecenia nie mogą mied wpływu na wyniki późniejszych poleceo. To samo dotyczy operacji 
pobierania  zmiennych  stanu  zapytania  i  odczytu  pikseli,  które  zwracają  stan  odpowiadający 
kompletnemu wykonaniu wszystkich  wcześniej wywoływanych  poleceo  OpenGL  (poza  przypadkami 
wyraźnie  określonymi  w  specyfikacji).  OpenGL  wiąże  dane  w  chwili  wywoływania  polecenia,  a 
wszelkie późniejsze zmiany danych nie mają wpływu na jego wynik. 
 

 

Rysunek 1 Diagram blokowy potoku renderingu OpenGL (źródło: specyfikacja OpenGL) 

 

Pierwszy  etap  potoku  renderingu  operuje  na  prymitywach  geometrycznych:  punktach, 

segmentach  linii  i  wielokątach,  które  są  opisane  przez  wierzchołki.  W  tym  etapie  wierzchołki  są 
przekształcane  i  oświetlane,  a  prymitywy  są  obcinane  do  bryły  widoku  w  celu  przygotowania  do 
następnego  etapu,  rasteryzacji.  Możliwe  jest  także  programowe  generowanie  nowych  prymitywów 
lub  usuwanie  istniejących.  Rasteryzator  generuje  szereg  fragmentów  -  elementów  bufora  ramki 
używanych  do  dwuwymiarowego  opisu  punktów,  segmentów  linii  lub  wielokątów.  Każdy  tak 
wyprodukowany fragment jest przekazywany do następnego etapu, gdzie wykonywane są operacje 
na poszczególnych fragmentach przed finalnym zapisem w buforze ramki. Operacje na buforze ramki 

background image

obejmują  m.in.  obsługę  wartości  bufora  głębokości,  mieszanie  kolorów  oraz  maskowanie  i  inne 
operacje  logiczne  na  wartościach  fragmentów.  Dane  bufora  ramki  mogą  byd  również  odczytywane 
lub kopiowane pomiędzy różnymi częściami bufora ramki. 
 

Poszczególne etapy potoku renderingu OpenGL poznamy bliżej w kolejnych odcinkach kursu. 

Podstawowa zasada OpenGL - powtarzalność 

 

Specyfikacja biblioteki OpenGL opisuje poszczególne operacje realizowane przez OpenGL, nie 

zakłada jednak i nie zapewnia zgodności na poziomie pikseli pomiędzy różnymi jej implementacjami. 
Poniżej krótko przedstawimy podstawową zasadę implementacji OpenGL – powtarzalnośd. 
 

Powtarzalnośd jest rozumiana jako identycznośd zawartości bufora ramki przy takich samych 

poleceniach i początkowych wartościach zmiennych stanu. Jest to szczególnie istotne przy typowych 
w  OpenGL  technikach  podwójnego  buforowania  i  algorytmach  wieloprzebiegowych,  bowiem  przy 
braku  powtarzalności  każdy  z  tworzonych  obrazów  mógłby  różnid  się  tworząc  widoczne  artefakty. 
Powtarzalnośd ma także dalej idące znaczenie, przykładowo dwie sceny różniące się tylko niewielkim 
przesunięciem  wielokąta  oczywiście  nie  będą  identycznie  wyrenderowane,  ale  zakładamy  zgodnośd 
tych fragmentów sceny, które nie obejmują pierwotnego i przesuniętego wielokąta. Oto podstawowe 
zasady powtarzalności: 

1.  Dla  danego  kontekstu  renderingu  i  zmiennych  stanu  bufora  ramki  dowolne  polecenie 

OpenGL da taki sam efekt koocowy w buforze ramki i wartościach zmiennych stanu. 

2.  Zmiany zawartości bufora ramki, buforów koloru do zapisu, parametrów testu nożycowego, 

masek  zapisu  składowych  oraz  wartości  czyszczących  bufory  nie  mogą  mied  wpływów 
ubocznych na inne zmienne stanu. 

3.  Specyfikacja  zaleca  także,  aby  zmiany  parametrów  bufora  szablonowego,  testu  głębokości, 

mieszania kolorów, operacji logicznych na pikselach, zapisu pikseli oraz przesuwania wartości 
głębokości wielokątów nie miały wpływu ubocznego na inne zmienne stanu. 

4.  Generowanie fragmentu jest niezmienne w stosunku do zasad wymienionych w zasadzie 2 i 

3. 

5.  Arytmetyka  operacji  na  fragmentach  jest  niezmienna  za  wyjątkiem  parametrów 

bezpośrednio je kontrolujących. 

6.  Obrazy  generowane  w  różnych  buforach  koloru  współdzielących  ten  sam  bufor  ramki, 

używające  równocześnie  lub  oddzielnie  tej  samej  sekwencji  poleceo  są  identyczne  na 
poziomie pikseli. 

7.  Identyczny  shader  wierzchołków  lub  fragmentów  (czyli  zgodny  na  poziomie  kodu 

źródłowego) wykonywany wielokrotnie dla takich samych danych wejściowych i wartościach 
zmiennych stanu generuje ten sam wynik. 

8.  Wszystkie  shadery  fragmentów,  które  warunkowo  lub  bezwarunkowo  przypisują 

gl_FragCoord.z  do  gl_FragDepth  są  niezmienne  w  zakresie  wartości  głębokości  w 
odniesieniu  do  każdego  innego  shadera,  dla  tych  fragmentów,  gdzie  przypisanie  do 
gl_FragDepth zostało zrealizowane. 

 

Chod  powyższe  zasady  określone  są  dla  implementatorów  OpenGL  warto o  nich  pamiętad  i 

wykorzystywad także w trakcie opracowywania programów. Częśd zasad odnosi się do szczegółów, z 
którymi będziemy się bliżej zapoznawad w kolejnych odcinkach niniejszego kursu. 

Przyjęte w kursie konwencje i zasady 

 

Programy w kursie  zasadniczo  wymagają dostępności  biblioteki OpenGL w  wersji 3.2,  ale  w 

wielu  przypadkach  wystarczy  dostępnośd  wersji  3.1  lub  3.0.  Przy  ich  pisaniu  wykorzystano  nowe 
funkcje  zarządzające  kontekstem  OpenGL,  co  powoduje,  że  programy  nie  mogą  byd  bezpośrednio 
uruchamiane  na  starszych  niż  3.0  wersjach  biblioteki.  Jednakże  częśd  z  nich,  po  odpowiednich 
modyfikacjach,  może  działad  z  OpenGL  2.0/2.1.  Programy  przykładowe  przy  tworzeniu  okien 
korzystają bezpośrednio z Xlib (systemu UNIX i Linux) oraz API WIN32 (systemy Microsoft Windows). 

background image

Fragmenty  programu  specyficzne  dla  danego  systemu  operacyjnego  są  oddzielone  od  elementów 
korzystających  z  biblioteki  OpenGL,  co  ułatwi  Czytelnikowi  ewentualną  migrację  programu  na 
wybraną platformę systemową lub programową. 
 

Wszystkie  programy  napisane  są  przy  użyciu  języka  C++  i  kompilowane  za  pomocą 

kompilatorów: Microsoft Visual C++ 2008 EE, Turbo C++ 2006 Explorer oraz kompilatora GCC 4.4 w 
systemie Linux Mandriva 2010. Programy testowano na karcie graficznej NVidia GeForce 8600GT. 
 

Do kompilacji programów nie są wymagane żadne dodatkowe zewnętrzne biblioteki. Jednak 

najczęściej używane funkcje  zostały pogrupowane w odrębne  pliki, które  mogą stanowią przydatną 
podręczną bibliotekę. 


Document Outline