Open GL Podstawy

background image

OpenGL

Podstawy

background image

Czym jest OpenGL ?

Czym jest OpenGL ?

"Programowy interfejs sprzętu graficznego"

Biblioteka zawierająca zbiór procedur ułatwiających

rysowanie grafiki dwu

i trójwymiarowej.

OpenGL nie jest, ani nie zawiera "enginu" grafiki

trójwymiarowej – służy jedynie do rysowania.

Procedury służące do rysowania skomplikowanych

modeli trójwymiarowych, ich animacji i transformacji

powinny być zaimplementowane przez programistę.

background image

OpenGL nie zawiera funkcji służących do tworzenia

okien i ich zarządzania (od tego jest np. GLUT), ani do

interakcji z użytkownikiem.

Procedury OpenGL służą do rysowania prymitywów

(punktów, odcinków, trójkątów), które mogą być

cieniowane, pokryte teksturami, przeźroczyste itd.

Implementacje OpenGL w różnych środowiskach

mogą, ale nie muszą wykorzystywać akceleracji

sprzętowej. Wykorzystanie dostępnych mechanizmów

zależy od implementacji OpenGL i jest przeźroczyste

dla programisty.

Czym jest OpenGL ?

Czym jest OpenGL ?

background image

Czym jest OpenGL ?

Czym jest OpenGL ?

Biblioteka OpenGL pracuje na zasadzie maszyny

stanów.

W praktyce polega to na tym, że w danym momencie

pracy jest ustawiony zbiór opcji wg. których rysowane

są prymitywy (np. kolor, sposób cieniowania itp.).

Sprawia to pewne problemy przy konstrukcji enginu do

np. gry komputerowej, gdyż zawsze, kiedy zaczynamy

rysować jakiś obiekt należy pamiętać, żeby ustawić

ponownie wszystkie parametry rysowania, gdyż

niektóre mogły zostać zmienione podczas rysowania

innych obiektów.

background image

Nazwy procedur w OpenGL (1)

Nazwy procedur w OpenGL (1)

W OpenGL praktycznie każda procedura posiada kilka

wersji.

Wersje te różnią się przede wszystkim typem

parametrów.

Jeżeli procedura może mieć wersje różniące się liczbą

parametrów, to do nazw konkretnych wersji dodawany

jest przyrostek (cyfra) określający liczbę tych

parametrów.

background image

Nazwy procedur w OpenGL (2)

Nazwy procedur w OpenGL (2)

W zależności od typu parametrów dodawane są

przyrostki, np:

d – double

f – float

i – int

Jeżeli istnieją wersje procedury, z których jedna

przyjmuje jako parametr liczbę, a druga wektor, to

dodawany jest również przyrostek v.

background image

Nazwy procedur w OpenGL (3)

Nazwy procedur w OpenGL (3)

Przykłady:

glVertex3d – posiada trzy parametry typu double

glLightfv – jako jeden z parametrów przyjmuje wektor liczb

typu float

background image

Czyszczenie okna (1)

Czyszczenie okna (1)

Wyczyszczenie zawartości okna polega na zapisaniu

każdego piksela takim samym kolorem.

Kolor czyszczenia można ustawić za pomocą

procedury glClearColor.

Składnia: void glClearColor( GLclampf red, GLclampf

green, GLclampf blue,

GLclampf alpha );

red, green, blue – to składowe koloru, alpha to stopień

przezroczystości.

background image

Czyszczenie okna (2)

Czyszczenie okna (2)

Do czyszczenia okna służy procedura glClear.

Składnia: void glClear( GLbitfield mask )

Parametr mask jest mapą bitową tworzoną przez

superpozycję pewnych stałych. Określa które bufory

powinny być czyszczone. Np.:

GL_COLOR_BUFFER_BIT – obraz

GL_DEPTH_BUFFER_BIT - z-bufor

background image

Wyświetlanie wyników rysowania

Wyświetlanie wyników rysowania

Jeżeli pracujemy w oknie z podwójnym buforowaniem

konieczna jest dodatkowa operacja aby wyświetlić

wynik rysowania.

W podwójnym buforowaniu rysujemy na niewidocznym

buforze. Aby go pokazać należy wywołać procedurę:

glutSwapBuffers;

Składnia: void glutSwapBuffers(void);

background image

Ćwiczenie

Ćwiczenie

Do części inicjującej szkieletu dodaj procedurę

określającą kolor czyszczenia na niebieski.

Do procedury odświeżającej okno dodaj wywołanie

procedury czyszczącej okno (czyść zarówno bufor

kolorów jak i z-bufor (to drugie przyda się w

następnych ćwiczeniach). Nie zapomnij na końcu

procedury odświeżającej dodać wywołania procedury

glutSwapBuffers.

W wyniku ćwiczenia powinieneś otrzymać okno, które

jest wypełnione kolorem niebieskim, zamiast

przypadkowych obrazów.

background image

Układy współrzędnych (1)

Układy współrzędnych (1)

Przestrzeń

obiektu

Przestrzeń

świata

Przestrzeń

oka

Przestrzeń

przycięcia

Znormalizowana

przestrzeń urządzenia

Przestrzeń

okna

Przekształcenie modelu

Przekształcenie widoku

Przekształcenie rzutowania

Podział perspektywiczny

Przekształcenie obrazu

i zakresu głębi

background image

Układy współrzędnych (2)

Układy współrzędnych (2)

Współrzędne homogeniczne punktu
w trójwymiarowej przestrzeni są reprezentowane
przez wektor 4 liczb: <x,y,z,w>.

Normalne współrzędne trójwymiarowe można
uzyskać dzieląc współrzędne x, y i z przez w.

Kolejne przekształcenia są reprezentowane
przez macierze 4x4.

Dzięki dodatkowej współrzędnej transformacje
wymagające dodania stałej do współrzędnej x, y
albo z (np. przesunięcie) mogą być również
przedstawione w postaci macierzy.

background image

Układy współrzędnych (3)

Układy współrzędnych (3)

Przestrzeń obiektu – układ współrzędnych

charakterystyczny dla pojedynczego rysowanego

obiektu.

Przestrzeń świata – układ współrzędnych rysowanej

sceny.

Przekształcenie modelu (model) – przekształcenie

przestrzeni obiektu w przestrzeń świata.

Przestrzeń oka – układ współrzędnych w którym

obserwator znajduje się w początku układu

współrzędnych, patrzy w kierunku rosnących wartości

współrzędnych z (w OpenGL malejących), a góra to

dodatni kierunek współrzędnej y.

background image

Układy współrzędnych (4)

Układy współrzędnych (4)

Przekształcenie widoku (view) – przekształcenie

przestrzeni świata w przestrzeń oka.

Przestrzeń przycięcia – przestrzeń definiuje widziany

obszar. Wszystko co jest widoczne znajduje się

wewnątrz sześcianu o krawędziach równoległych do

osi układu współrzędnych. Każdy widoczny punkt musi

spełniać warunki: -w≤x≤w, -w≤y≤w, -w≤z≤w.

Przekształcenie rzutowania (projection) –

przekształcenie przestrzeni oka w przestrzeń

przycięcia.

background image

Układy współrzędnych (5)

Układy współrzędnych (5)

Znormalizowana przestrzeń urządzenia –

w przestrzeni urządzenia wszystkie współrzędne

homogeniczne są przekształcone do ich reprezentacji

trójwymiarowej (w=1).

Podział perspektywiczny – transformacja przestrzeni

przycięcia do znormalizowanej przestrzeni urządzenia.

Przestrzeń okna – przestrzeń w której współrzędne są

wyrażone w pikselach w oknie,

w którym obraz jest ostatecznie rysowany.

background image

Układy współrzędnych (6)

Układy współrzędnych (6)

W OpenGL macierze przekształceń modelu
i widoku są połączone w macierz model – widok będącą

złożeniem obu tych transformacji. Postąpiono w ten
sposób, gdyż w zasadzie jedna z tych macierzy może

zastąpić drugą.

Możemy modyfikować w dowolny sposób macierz model –

widok i macierz rzutowania.

Przekształcenie obrazu można modyfikować za pomocą

procedury glViewport, oraz za pomocą procedur biblioteki
GLUT. Tym przekształceniem nie będziemy się zajmować

na zajęciach.

Procedurę glViewport wykorzystuje się do zainicjowania
macierzy przekształcenia obrazu (robione automatycznie
przez GLUT) oraz w sytuacjach, gdy okno zmienia

rozmiar.

background image

Układy współrzędnych (7)

Układy współrzędnych (7)

Aby przełączyć OpenGL w tryb modyfikacji
odpowiedniej macierzy należy wykorzystać
procedurę void glMatrixMode( GLenum mode ),
gdzie mode wyznacza którą z macierzy należy
modyfikować:

GL_PROJECTION – macierz rzutowania

GL_MODELVIEW – macierz model – widok.

background image

Układy współrzędnych (8)

Układy współrzędnych (8)

Obie macierze modyfikuje się poprzez:

Załadowanie macierzy jednostkowej za pomocą procedury

void glLoadIdentity().

Mnożenie aktualnej macierzy przez macierze reprezentujące
różne transformacje.

W przypadku macierzy rzutowania, załadowaną

macierz jednostkową mnożymy razy macierz

rzutowania równoległego (procedura glOrtho) lub

macierz rzutu perspektywicznego (procedura

gluPerspective)

background image

Układy współrzędnych (9)

Układy współrzędnych (9)

W ćwiczeniach będziemy korzystać jedynie

z rzutu perspektywicznego.

Procedura gluPerspective ma następującą składnię:

void gluPerspective( GLdouble fovy, GLdouble aspect,

GLdouble zNear,

GLdouble zFar ), gdzie:

fovy to kąt widzenia (stopnie)

aspect to stosunek szerokości okna do jego wysokości

zNear to odległość bliższej płaszczyzny obcinania

zFar to odległość dalszej płaszczyzny obcinania

background image

Układy współrzędnych (10)

Układy współrzędnych (10)

Poniższy przykładowy kod należy umieścić w części

inicjującej szkieletu.

..........

glMatrixMode(GL_PROJECTION);

//Przełączenie w tryb macierzy rzutowania

glLoadIdentity();

//Załadowanie macierzy jednostkowej

gluPerspective(55,1,1,50);

//Pomnożenie jej razy macierz rzutu perspektywicznego

...........

Przykład ten konfiguruje OpenGL do wykonywania

rzutowania perspektywicznego, z kątem widzenia 55

stopni, stosunkiem wysokości do szerokości 1, bliskiej

płaszczyźnie obcinania w odległości 1 i dalekiej
płaszczyzny obcinania w odległości 50.

background image

Układy współrzędnych (11)

Układy współrzędnych (11)

Macierz widok – model zawiera złożenie transformacji

translacji, obrotów i skalowania, które przekształca

współrzędne w przestrzeni modelu we współrzędne w

przestrzeni oka.

Procedury służące do obrotu układu współrzędnych,

translacji i skalowania zostaną podane później. Do

następnego ćwiczenia przyda się procedura gluLookAt

background image

Układy współrzędnych (12)

Układy współrzędnych (12)

Procedura gluLookAt wykonuje taką transformację

układu współrzędnych, aby odpowiadał on widokowi

jaki posiada obserwator o określonym położeniu

patrzący na konkretny punkt – innymi słowy mnoży

aktualnie modyfikowaną macierz razy macierz
przekształcenia widoku.

Składnia: void gluLookAt(

GLdouble eyex, GLdouble eyey, GLdouble eyez,
GLdouble centerx, GLdouble centery, GLdouble

centerz,

GLdouble upx, GLdouble upy, GLdouble upz )

background image

Układy współrzędnych (13)

Układy współrzędnych (13)

Poszczególne parametry tej procedury mają

następujące znaczenie:

eyex, eyey, eyez – współrzędne obserwatora

centerx, centery, centerz – obserwowany punkt

upx, upy, upz – wektor określający "górę" obserwatora

background image

Układ współrzędnych (14)

Układ współrzędnych (14)

Przykładowy kod wykorzystujący opisane wcześniej

procedury przedstawiono poniżej. Można go umieścić

zarówno w części inicjującej jak i rysującej, ale od tego

zależy sposób wykonywania dalszych ćwiczeń.

Sugeruję umieszczenie go w części rysującej.

.............

glMatrixMode(GL_MODELVIEW);

//Przełączenie w tryb macierzy widoku modelu

glLoadIdentity();

//Załadowanie macierzy jednostkowej

gluLookAt(7,7,7,0,0,0,0,1,0);

//Patrzy z punktu <7,7,7> na <0,0,0>, głowa prosto ;)

.............

background image

Prosty obiekt

Prosty obiekt

Istnieje wiele procedur rysujących proste obiekty. Oto

kilka z nich (nazwy są samotłumaczące ;))

void glutSolidSphere(GLdouble radius, GLint slices, GLint stacks);

void glutWireSphere(GLdouble radius, GLint slices, GLint stacks);

void glutSolidCube(GLdouble size);

void glutWireCube(GLdouble size);

void glutSolidCone(GLdouble base, GLdouble height, GLint slices, GLint

stacks);

void glutWireCone(GLdouble base, GLdouble height, GLint slices, GLint

stacks);

void glutSolidTorus(GLdouble innerRadius, GLdouble outerRadius, GLint

nsides, GLint rings);

void glutWireTorus(GLdouble innerRadius, GLdouble outerRadius, GLint

nsides, GLint rings);

void glutSolidTeapot(GLdouble size);

void glutWireTeapot(GLdouble size);

background image

Ćwiczenie

Ćwiczenie

Ćwiczenie polega na modyfikacji wyniku poprzedniego

ćwiczenia.

Zmień kolor tła na czarny.

Narysuj szkielet torusa (glutWireTorus)

o promieniu wewnętrznym 1 a zewnętrznym 3. Nie

zapomnij o ustawieniu obserwatora!

Wywołanie glutWireTorus powinieneś

umieścić w procedurze rysującej po

ustawieniu obserwatora, ale przed

glSwapBuffers;

background image

Transformacje układu współrzędnych (1)

Transformacje układu współrzędnych (1)

Obrót obiektu można wykonać poprzez pomnożenie

macierzy model – widok przez macierz obrotu.

Procedura void glRotated( GLdouble angle, GLdouble

x, GLdouble y, GLdouble z ) mnoży aktualnie

modyfikowaną macierz przez macierz obrotu o kąt

angle wokół osi wyznaczonej przez wektor <x,y,z>.

background image

Transformacje układu współrzędnych (2)

Transformacje układu współrzędnych (2)

Procedura void glScaled( GLdouble x, GLdouble y,

GLdouble z ) mnoży aktualnie modyfikowaną macierz

razy macierz skalującą. Kolejne parametry procedury

to współczynniki skalowania na poszczególnych

osiach układu współrzędnych.

Procedura void glTranslated( GLdouble x, GLdouble y,

GLdouble z ) mnoży aktualnie modyfikowaną macierz

razy macierz translacji. Kolejne parametry procedury
to współrzędne wektora, o który następuje

przesunięcie.

background image

Ćwiczenie

Ćwiczenie

Umieść przed instrukcją rysującą torus (ale za

instrukcjami definiującymi obserwatora) instrukcję

obracającą układ współrzędnych dookoła osi Y

(wektor <0,1,0>) o 60 stopni.

background image

Animacja (1)

Animacja (1)

Animację można zrealizować za pomocą specjalnej

procedury callback wywoływanej najczęściej jak się

da.

Do ustawienia tej procedury służy procedura:

void glutIdleFunc(void (*func)(void));

Jako parametr powinno się przekazać nazwę

procedury, która nie posiada parametrów. Procedura

ta będzie wywoływana przez glut.

background image

Animacja (2)

Animacja (2)

Procedura callback powinna modyfikować wartości

jakichś zmiennych na podstawie których rysowany jest

obraz w procedurze rysującej i wywołać ponowne

narysowanie obrazu.

Aby wywołać ponowne narysowanie obrazu należy

wywołać procedurę:

void glutPostRedisplay(void);

background image

Animacja (3)

Animacja (3)

Przykład fragmentów kodu definiujących animację:

float

speed=360;

//360 stopni/s

int

lastTime=0;

float

angle;

void

displayFrame(

void

) {

............

glRotated(angle,1,0,0);

glutWireTorus(1,3,10,10);

glutSwapBuffers();

}

void

nextFrame(void) {

int

actTime=glutGet(GLUT_ELAPSED_TIME);

int

interval=actTime-lastTime;

lastTime=actTime;

angle+=speed*interval/1000.0;

if

(angle>360) angle-=360;

glutPostRedisplay();

}

int

main (....) {

.......

glutIdleFunc(nextFrame);

.......

glutMainLoop();

}

background image

Ćwiczenie

Ćwiczenie

Zmodyfikuj poprzedni program tak, aby torus obracał się wokół
dwóch osi (X i Y). Wokół osi X z prędkością 120 stopni/s a

wokół osi Y z prędkością 240 stopni/s.

background image

Kolory

Kolory

Kolor obiektu który ma być narysowany ustawia się za

pomocą procedury: void glColor3d( GLdouble red,

GLdouble green, GLdouble blue )

Poszczególne parametry oznaczają udział składowych

w wynikowym kolorze i przyjmują wartości z przedziału

od 0 do 1.

background image

Ćwiczenie

Ćwiczenie

Zmodyfikuj poprzedni program tak, aby animowany

torus był niebieski.

Spróbuj zastąpić procedurę rysującą siatkę torusa

procedurą rysującą pełen torus (glutSolidTorus). Czy

efekt jest zadowalający ?

background image

Cieniowanie (1)

Cieniowanie (1)

Aby włączyć cieniowanie należy wykonać nastepującą

instrukcję:

glEnable(GL_LIGHTING);

glEnable służy do włączania wielu różnych opcji,
które będą stopniowo wprowadzane.

Po włączeniu cieniowania należy włączyć źródło
światła:

glEnable(GL_LIGHT0);

Domyślnie źródło światła o numerze 0 ma kolor
biały i znajduje się w nieskończoności, za
obserwatorem.

background image

Cieniowanie (2)

Cieniowanie (2)

Kolejnym krokiem jest włączenie typu cieniowania.

Zaimplementowane są dwa algorytmy: płaskie

i gładkie (Gourauda).

Typ cieniowania wybieramy za pomocą procedury void

glShadeModel( GLenum mode ), która przyjmuje

parametry:

GL_FLAT – cieniowanie płaskie

GL_SMOOTH – cieniowanie gładkie

background image

Cieniowanie (3)

Cieniowanie (3)

Przykładowy kod należy umieścić w części
inicjującej:

glEnable(GL_LIGHTING);

glEnable(GL_LIGHT0);

glShadeModel(GL_SMOOTH);

Powyższy kod włącza cieniowanie, zerowe źródło
światła i ustawia cieniowanie gładkie

background image

Z-Bufor

Z-Bufor

Z-Bufor służy do usuwania niewidocznych

powierzchni.

Bufor ten przechowuje informację w jakiej odległości

od obserwatora znajduje się aktualnie narysowany

piksel.

Jeżeli kolejny rysowany w tym miejscu piksel jest

dalej, to jest on pomijany, gdyż obecny przesłania go.

Aby włączyć Z-Bufor należy wykonać instrukcję:

glEnable(GL_DEPTH_TEST);

//W części inicjującej

background image

Wstęp do materiałów

Wstęp do materiałów

Każdy obiekt jest zbudowany z "materiału"

Materiałem nazywamy zbiór parametrów

określających sposób cieniowania obiektu, oraz np.

jego teksturę.

Aby obiekt złożony z wielokątów (a nie jego szkielet)

miał kolor taki jak aktywny należy włączyć śledzenie

przez materiał kolorów za pomocą instrukcji:

glEnable(GL_COLOR_MATERIAL);

//W części inicjującej

background image

Ćwiczenie

Ćwiczenie

Zastąp instrukcję rysującą szkielet torusa instrukcją

rysującą pełen torus (auxSolidTorus) jeśli tego nie

zrobiłeś w poprzednim ćwiczeniu.

Włącz cieniowanie, zerowe światło, typ cieniowania

płaski.

Włącz Z-Bufor i śledzenie kolorów przez materiał.

Zmień model cieniowania na gładki. Zaobserwuj
różnice.

background image

Interakcja z użytkownikiem (1)

Interakcja z użytkownikiem (1)

Biblioteka GLUT pozwala na zdefiniowanie procedury

callback wywoływanej w momencie naciśnięcia

klawisza.

Procedura ta powinna posiadać następującą

sygnaturę: void keyEvent(unsigned char c, int x, int y).

Oczywiście nazwa jest dowolna.

Procedurę callback rejestruje się za pomocą

procedury void glutKeyboardFunc(

void (*func)(unsigned char key,int x, int y));

background image

Interakcja z użytkownikiem (2)

Interakcja z użytkownikiem (2)

Podobnie jak w przypadku animacji wywołana

procedura powinna modyfikować parametry

wyświetlania klatki przez procedurę rysującą.

Przykład:

void

keyEvent(

unsigned

char

c,

int

x,

int

y) {

if

(c=='a') angle=(angle+5)%360;

if

(c=='z') angle=(angle-5)%360;

glutPostRedisplay();

}

int

main (....) {

.......
glutKeyboardFunc(keyEvent);

.......
glutMainLoop();

}

background image

Ćwiczenie

Ćwiczenie

Zakomentuj zawartość procedury nextFrame.

Zastąp procedurę rysującą torus inną procedurą,

rysującą jakiś obiekt trójwymiarowy.

Utwórz procedurę callback pozwalającą na obracanie

tym obiektem wokół wszystkich trzech osi układu

współrzędnych.

background image

Stos macierzy (1)

Stos macierzy (1)

W trakcie rysowania jednej klatki można wielokrotnie

modyfikować macierz widoku modelu w celu

rysowania różnych obiektów.

Można sobie ułatwić te transformacje zapamiętując

aktualny stan macierzy. Do zapamiętania aktualnej

macierzy można wykorzystać stos macierzy.

Stos macierzy jest obsługiwany za pomocą

bezparametrowych procedur glPushMatrix()

i glPopMatrix().

background image

Stos macierzy (2)

Stos macierzy (2)

Procedura glPushMatrix powoduje skopiowanie

i umieszczenie na stosie aktualnej macierzy.

Procedura glPopMatrix powoduje odczytanie ze stosu

macierzy i zastąpienie nią aktualnej macierzy.

Na następnym slajdzie zostanie przedstawiony

przykład wykorzystujący procedurę glutSolidCube.

Procedura ta rysuje sześcian. Jej jedynym

parametrem jest długość krawędzi.

background image

Stos macierzy (3)

Stos macierzy (3)

Poniższy przykład rysuje obiekt złożony z wielu
sześcianów:

glColor3d(1,0,0);
glutSolidCube(1);
glColor3d(0,1,0);
glPushMatrix();

glTranslatef(0.5,0,0);

glutSolidCube(0.25);

glPopMatrix();
glPushMatrix();

glTranslatef(-0.5,0,0);

glutSolidCube(0.25);

glPopMatrix();
glPushMatrix();

glTranslatef(0,0.5,0);

glutSolidCube(0.25);

glPopMatrix();
glPushMatrix();

glTranslatef(0,-0.5,0);

glutSolidCube(0.25);

glPopMatrix();
glPushMatrix();

glTranslatef(0,0,0.5);

glutSolidCube(0.25);

glPopMatrix();
glPushMatrix();

glTranslatef(0,0,-0.5);

glutSolidCube(0.25);

glPopMatrix();

background image

Ćwiczenie

Ćwiczenie

Zastanów się jak wygląda obiekt rysowany przez kod z

poprzedniego slajdu.

Zastąp dotychczasowy kod rysujący torus lub inny

obiekt kodem z przykładu. Czy takiego wyniku

oczekiwałeś ?

Zastanów się jak stworzyć dwa torusy obracające się

jak „w trybach”:

background image

Rysowanie dowolnych obiektów (1)

Rysowanie dowolnych obiektów (1)

Dotychczas korzystaliśmy z gotowych procedur, które

rysowały całe obiekty – sześciany, torusy

i inne.

Można jednak narysować dowolny obiekt korzystając z

takich składowych jak: linie, trójkąty i czworokąty itp.

Aby narysować jakiś obiekt, można wykorzystać

procedury glDrawArrays i glDrawElements.

background image

Rysowanie dowolnych obiektów (2)

Rysowanie dowolnych obiektów (2)

Rysowanie z użyciem glDrawArrays:

float smallQuadVertices[]={ //Tablica współrzędnych wierzchołków

-1,-1,0,

1,-1,0,

1, 1,0,
-1, 1,0

};

float smallQuadColors[]={ //Tablica kolorów wierzchołków

1,0,0,

1,0,0,

1,0,0,

1,0,0

};
int smallQuadVertexCount=4; //Liczba wierzchołków w tablicy

....................

glEnableClientState( GL_VERTEX_ARRAY );

glEnableClientState( GL_COLOR_ARRAY );

glVertexPointer( 3, GL_FLOAT, 0, smallQuadVertices );

glColorPointer( 3, GL_FLOAT, 0, smallQuadColors );
glDrawArrays( GL_QUADS, 0, smallQuadVertexCount );

glDisableClientState( GL_VERTEX_ARRAY );

glDisableClientState( GL_COLOR_ARRAY );

background image

Rysowanie dowolnych obiektów (3)

Rysowanie dowolnych obiektów (3)

float geomVertices[]={
0,4.08,0, 0,0,2.88,

0,4.08,0, 2.5,0,-1.44,
0,4.08,0, -2.5,0,-1.44,

0,0,2.88, -2.5,0,-1.44,
0,0,2.88, 2.5,0,-1.44,

-2.5,0,-1.44, 2.5,0,-1.44
};

int geomVertexCount=12;

..........

glColor3d(0.5,1,0.5);

glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer( 3, GL_FLOAT, 0,

geomVertices);
glDrawArrays(GL_LINES,0,geomVertexCount);

glDisableClientState(GL_VERTEX_ARRAY);

float geomVertices[]={
0,4.08,0, 0,0,2.88, -2.5,0,-1.44,

0,4.08,0, 0,0,2.88, 2.5,0,-1.44,
0,4.08,0, 2.5,0,-1.44,-2.5,0,-1.44,

2.5,0,-1.44, -2.5,0,-1.44, 0,0,2.88
};

float geomColors[]={

1,0,0, 1,0,0, 1,0,0,
0,1,0, 0,1,0, 0,1,0,

0,0,1, 0,0,1, 0,0,1,

1,1,0, 1,1,0, 1,1,0
};

int geomVertexCount=12;

.............

glEnableClientState( GL_VERTEX_ARRAY );
glEnableClientState( GL_COLOR_ARRAY );

glVertexPointer( 3, GL_FLOAT, 0,
geomVertices);

glColorPointer( 3, GL_FLOAT, 0,

geomColors);
glDrawArrays(GL_TRIANGLES,0,

geomVertexCount);
glDisableClientState( GL_VERTEX_ARRAY );

glDisableClientState( GL_COLOR_ARRAY );

background image

Rysowanie dowolnych obiektów (4)

Rysowanie dowolnych obiektów (4)

Rysowanie z użyciem glDrawElements:

float geomVertices[]={

0,4.08,0, 0,0,2.88, -2.5,0,-1.44, 2.5,0,-1.44,

};

float geomColors[]={

1,0,0, 0,1,0, 0,0,1, 1,1,0

};

unsigned int geomIndexes[] ={

0,1,2, 0,1,3, 0,2,3, 3,2,1

};

int geomIndexCount=12;
int geomVertexCount=4;

...............

glEnableClientState( GL_VERTEX_ARRAY );

glEnableClientState( GL_COLOR_ARRAY );

glVertexPointer( 3, GL_FLOAT, 0, geomVertices);
glColorPointer( 3, GL_FLOAT, 0, geomColors);

glDrawElements(GL_TRIANGLES,geomIndexCount, GL_UNSIGNED_INT,geomIndexes);

glDisableClientState( GL_VERTEX_ARRAY );

glDisableClientState( GL_COLOR_ARRAY );

background image

Vertex Buffer Objects (1)

Vertex Buffer Objects (1)

Rysując za pomocą glDrawArrays/glDrawElements za

każdym razem przesyłamy współrzędne wierzchołków

z pamięci komputera do pamięci karty graficznej. Dla

dużych modeli może to nie być wydajne.

Możliwe jest załadowanie tablic wykorzystywanych

przez procedury glDrawArrays/glDrawElements do

pamięci karty graficznej za pomocą tzw. Vertex Buffer

Objects.

background image

Vertex Buffer Objects(2)

Vertex Buffer Objects(2)

Wykorzystanie VBO razem z glDrawArrays()

Załadowanie tablic do VBO:

//Tablice takie jak dla ostatniego przykładu z glDrawArrays()
GLuint geomVerticesId;
Gluint geomColorsId;

.......................

//Wygenerowanie uchwytu na "bufor"
glGenBuffers(1,&geomVerticesId);
//Wybranie aktywnego "bufora"
glBindBuffer(GL_ARRAY_BUFFER,geomVerticesId);
//Przeniesienie danych do bufora
glBufferData(GL_ARRAY_BUFFER,
geomVertexCount*3*sizeof(float), geomVertices, GL_STATIC_DRAW );

glGenBuffers(1,&geomColorsId);
glBindBuffer(GL_ARRAY_BUFFER,geomColorsId);
glBufferData(GL_ARRAY_BUFFER,
geomVertexCount*3*sizeof(float), geomColors, GL_STATIC_DRAW );

background image

Vertex Buffer Objects (3)

Vertex Buffer Objects (3)

Wykorzystanie VBO razem glDrawArrays()

Wykorzystanie VBO podczas rysowania:

glEnableClientState( GL_VERTEX_ARRAY );
glEnableClientState( GL_COLOR_ARRAY );

glBindBuffer(GL_ARRAY_BUFFER,geomVerticesId);

glVertexPointer( 3, GL_FLOAT, 0, NULL);
glBindBuffer(GL_ARRAY_BUFFER,geomColorsId);

glColorPointer( 3, GL_FLOAT, 0, NULL);

glBindBuffer(GL_ARRAY_BUFFER,0);

glDrawArrays( GL_TRIANGLES, 0, geomVertexCount );

glDisableClientState( GL_VERTEX_ARRAY );
glDisableClientState( GL_

COLOR_ARRAY );

background image

Vertex Buffer Objects (4)

Vertex Buffer Objects (4)

Wykorzystanie VBO razem z glDrawElements()

Załadowanie tablicy do VBO

//Tablice takie jak w ostatnim przykłądzie dla glDrawElements()
GLuint geomVerticesId;
GLuint geomColorsId;
GLuint geomIndexesId;

...........

glGenBuffers(1,&geomVerticesId);
glBindBuffer(GL_ARRAY_BUFFER,geomVerticesId);
glBufferData(GL_ARRAY_BUFFER,
geomVertexCount*3*sizeof(float), geomVertices, GL_STATIC_DRAW );

glGenBuffers(1,&geomColorsId);
glBindBuffer(GL_ARRAY_BUFFER,geomColorsId);
glBufferData(GL_ARRAY_BUFFER,
geomVertexCount*3*sizeof(float), geomColors, GL_STATIC_DRAW );

glGenBuffers(1,&geomIndexesId);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,geomIndexesId);
glBufferData(GL_ELEMENT_ARRAY_BUFFER,
geomIndexCount*3*sizeof(unsigned int), geomIndexes, GL_STATIC_DRAW );

background image

Vertex Buffer Objects (5)

Vertex Buffer Objects (5)

Wykorzystanie VBO razem glDrawElements()

Wykorzystanie VBO podczas rysowania:

glEnableClientState( GL_VERTEX_ARRAY );
glEnableClientState( GL_COLOR_ARRAY );

glBindBuffer(GL_ARRAY_BUFFER,geomVerticesId);
glVertexPointer( 3, GL_FLOAT, 0, NULL);
glBindBuffer(GL_ARRAY_BUFFER,geomColorsId);
glColorPointer( 3, GL_FLOAT, 0, NULL);
glBindBuffer(GL_ARRAY_BUFFER,0);

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,geomIndexesId);
glDrawElements( GL_TRIANGLES, geomIndexCount, GL_UNSIGNED_INT, NULL );
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,0);

glDisableClientState( GL_VERTEX_ARRAY );
glDisableClientState( GL_COLOR_ARRAY );

background image

Vertex Buffer Objects (6)

Vertex Buffer Objects (6)

Usuwanie bufora VBO z pamięci:

glDeleteBuffers(1,&geomVerticesId);

background image

Ćwiczenie

Ćwiczenie

Zakomentuj kod włączający cieniowanie (włączenie

cieniowania, włączenie światła

i ustawienie typu cieniowania).

Napisz kod, który rysuje sześcian. Opcjonalnie użyj

VBO. Każda ściana powinna być innego koloru.

background image

Teksturowanie (1)

Teksturowanie (1)

Teksturowaniem nazywamy nakładanie na ściany

wyświetlanych brył obrazków tekstur (potocznie

nazywanych po prostu "teksturami").

W OpenGL istnieją mechanizmy pozwalające na łatwe

oteksturowanie modelu, ale nie ma procedur

wczytujących tekstury z plików graficznych – to trzeba

zaimplementować samemu.

Podczas ćwiczeń wykorzystamy bibliotekę do odczytu

plików TGA, którą można sciągnąć z:

http://gpwiki.org/index.php/LoadTGACpp

background image

Teksturowanie (2)

Teksturowanie (2)

Biblioteka definiuje klasę TGAImg, która zawiera

metody takie jak:

int Load(char* szFileName) – wczytuje plik, zwraca wartość
IMG_OK, jeśli obraz odczyta się w porządku

int GetBPP() - zwraca liczbę bitów na piksel

int GetWidth() - zwraca szerokość obrazka

int GetHeight() - zwraca wysokość obrazka

unsigned char* GetImg() - zwraca wskaźnik do danych
obrazka

unsigned char* GetPalette() - zwraca wskaźnik do danych
palety obrazka

background image

Teksturowanie (3)

Teksturowanie (3)

Kiedy obraz zostanie wczytany do pamięci należy go

zaimportować do OpenGL.

Wykonuje się to za pomocą trzech funkcji OpenGL:

glGenTextures()

glBindTexture()

glTexImage2D()

background image

Teksturowanie (4) - glGenTextures

Teksturowanie (4) - glGenTextures

Służy do inicjowania uchwytów tekstur.

void glGenTextures(GLsizei n, GLuint *textures)

n – liczba uchwytów do zainicjowania

textures – tablica zmiennych typu Gluint, która ma

przechowywać nowe uchwyty

Jeżeli inicjujemy tylko jeden uchwyt można

zastosować następujący kod:

GLuint tex;

//Uchwyt

..................

glGenTextures(1,&tex);

//Zainicjuj jeden uchwyt

background image

Teksturowanie (5) - glBindTexture

Teksturowanie (5) - glBindTexture

Ustawia aktualny uchwyt tesktury.

void glBindTexture(GLenum target,

GLuint texture);

target – typ tekstury, na naszych zajęciach zawsze

GL_TEXTURE_2D

texture – uchwyt, który ma być aktualny

background image

Teksturowanie (6) - glTexImage2D

Teksturowanie (6) - glTexImage2D

Wczytuje obrazek do OpenGL, obrazek przechowywany
w obiekcie klasy TGAImg można po wykonaniu tej

procedury usunąć z pamięci.

void glTexImage2D( Glenum target, GLint level,
GLint internalformat, GLsizei width, GLsizei height,
GLint border, GLenum format, GLenum type,
const GLvoid *pixels );

target – zawsze GL_TEXTURE_2D

level – poziom mipmapy, dla nas zawsze 0

internalformat – liczba składowych koloru:

Dla obrazków 32 bitowych 4 (RGBA)

Dla obrazków 24 bitowych 3 (RGB)

background image

Teksturowanie (7) – glTexImage2D

Teksturowanie (7) – glTexImage2D

width – szerokość obrazka (potęga dwójki)

height – wysokość obrazka (potęga dwójki)

border – na zajęciach zawsze 0

format:

GL_RGBA dla obrazków 32 bitowych

GL_RGB dla obrazków 24 bitowych

type – na zajęciach GL_UNSIGNED_BYTE

pixels – wskaźnik do obszaru pamięci, w którym zapisano
dane obrazka, można go uzyskać korzystając z metody

GetImg klasy TGAImg.

background image

Teksturowanie (8)

Teksturowanie (8)

Do załadowania pojedynczej tekstury można użyć

następującego kodu:

if

(img.Load(TexName)==IMG_OK) {

glGenTextures(1,&tex);

//Zainicjuj uchwyt tex

glBindTexture(GL_TEXTURE_2D,tex);

//Przetwarzaj uchwyt tex

if

(img.GetBPP()==24)

//Obrazek 24bit

glTexImage2D(GL_TEXTURE_2D,0,3,img.GetWidth(),img.GetHeight(),0,

GL_RGB,GL_UNSIGNED_BYTE,img.GetImg());

else

if

(img.GetBPP()==32)

//Obrazek 32bit

glTexImage2D(GL_TEXTURE_2D,0,4,img.GetWidth(),img.GetHeight(),0,

GL_RGBA,GL_UNSIGNED_BYTE,img.GetImg());

else

{

//Obrazek 16 albo 8 bit, takimi się nie przejmujemy

}

}

else

{

//błąd

}

background image

Teksturowanie (9) - glDeleteTextures

Teksturowanie (9) - glDeleteTextures

Zwalnia pamięć zajmowaną przez tekstury

o zadanych uchwytach.

void glDeleteTextures(GLsizei n,

GLuint *textures)

n – liczba uchwytów do zwolnienia

textures – tablica zmiennych typu Gluint, która przechowuje

usuwane uchwyty

background image

Teksturowanie (10)

Teksturowanie (10)

Aby móc używać tekstur przy rysowaniu obrazów należy jeszcze ustawić

kilka parametrów teksturowania:

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

Powyższe parametry ustawiają zawijanie tekstur i filtrowanie dwuliniowe

(bilinear filtering) bez mipmap. Powyższe ustawienia będziemy

wykorzystywać podczas zajęć, ale sugeruję poeksperymentowanie z nimi w

domu. Ustawienia te można zmienić w dowolnym momencie działania

programu.

background image

Teksturowanie (11)

Teksturowanie (11)

Ostatnią czynnością jaką należy wykonać przed

rysowaniem teksturowanych obiektów jest włączenie

teksturowania:

glEnable(GL_TEXTURE_2D)

W trakcie pracy programu można włączać

i wyłączać (glDisable) teksturowanie.

background image

Teksturowanie (12)

Teksturowanie (12)

Aby rysowany obiekt pokryć teksturą należy

z każdym jego wierzchołkiem skojarzyć współrzędne

tekstury mu odpowiadające.

Aby móc podać współrzędne teksturowania należy

umieścić je w tablicy, a następnie wskazać je

poleceniu glDrawArrays/glDrawElements za pomocą

glTexCoordPointer.

Aby aktywować użycie wspórzędnych teksturowania,

należy użyć polecenia:
glEnableClientState(GL_TEXTURE_COORD_ARRAY)

background image

Teksturowanie (13)

Teksturowanie (13)

Poniższy przykład rysuje oteksturowany kwadrat:

float geomVertices[]={
-1,-1,0, 1,-1, 0, 1,1,0, -1,1,0
};

float geomTexCoords[]={
0,0, 1,0, 1,1, 0,1
};

int geomVertexCount=4;

............

glBindTexture(GL_TEXTURE_2D,tex);

glEnableClientState( GL_VERTEX_ARRAY );

glEnableClientState( GL_TEXTURE_COORD_ARRAY );

glVertexPointer( 3, GL_FLOAT, 0, geomVertices);

glTexCoordPointer( 2, GL_FLOAT, 0, geomTexCoords);

glDrawArrays(GL_QUADS,0, geomVertexCount);

glDisableClientState( GL_VERTEX_ARRAY );

glDisableClientState( GL_TEXTURE_COORD_ARRAY );

background image

Ćwiczenie

Ćwiczenie

Zmodyfikuj program z poprzednich ćwiczeń tak, aby

rysował i animował teksturowany sześcian. Na

potrzeby ćwiczenia wyłącz cieniowanie.

background image

Zaawansowane cieniowanie (1)

Zaawansowane cieniowanie (1)

Aby OpenGL poprawnie obliczał ile światła przypada

na każdą ścianę lub każdy wierzchołek bryły, musi

znać normalne do powierzchni.

Normalna jest wektorem który jest prostopadły do

powierzchni. Normalną można obliczyć znając trzy

punkty definiujące tę powierzchnię.

OpenGL wymaga, aby wektory normalne miały

jednostkową długość.

background image

Zaawansowane cieniowanie (2)

Zaawansowane cieniowanie (2)

Punkty definiujące powierzchnię stanowią początek i 2

końce dwóch wektorów.

Mając dane współrzędne wektorów a i b,
nieznormalizowany wektor prostopadły do płaszczyzny

można znaleźć obliczając wyznacznik przedstawiony

na następnym slajdzie.

n

a

b

background image

Zaawansowanie cieniowanie (3)

Zaawansowanie cieniowanie (3)

Normalną można uzyskać z następującego

wyznacznika:

gdzie i, j i k to wektory tworzące układ współrzędnych,

odpowiednio <1,0,0>, <0,1,0> i <0,0,1>.

Uwaga ! Zamiana wektorów powoduje zmianę zwrotu

normalnej na przeciwny !

n=

i

j

k

a

x

a

y

a

z

b

x

b

y

b

z

background image

Zaawansowane cieniowanie (4)

Zaawansowane cieniowanie (4)

Aby znormalizować długość wektora normalnego

należy wszystkie jego współrzędne podzielić przez

długość wektora.

Można również włączyć automatyczną normalizację

długości wektora normalnego za pomocą wywołania:

glEnable(GL_NORMALIZE);

background image

Zawansowane cieniowanie (5)

Zawansowane cieniowanie (5)

Współrzędne wektora normalnego podajemy podobnie

jak współrzędne tekstur, kolory, i współrzędne

wierzchołków – potrzebna jest tablica z odpowiednimi

danymi.

Tablicę wiążemy z poleceniem glDrawArrays lub

glDrawElements za pomocą glNormalPointer.

Aby aktywować użycie tablicy z normalnymi, należy

użyć polecenia:
glEnableClientState(GL_NORMAL_ARRAY)

background image

Zaawansowane cieniowanie (6)

Zaawansowane cieniowanie (6)

Przykład narysowania oteksturowanego i
ocieniowanego kwadratu:

float geomVertices[]={
-1,-1,0, 1,-1, 0, 1,1,0, -1,1,0
};
float geomTexCoords[]={
0,0, 1,0, 1,1, 0,1
};

float geomNormals[]={
0,0,1, 0,0,1, 0,0,1, 0,0,1
};

int geomVertexCount=4;
............
glBindTexture(GL_TEXTURE_2D,tex);

glEnableClientState( GL_VERTEX_ARRAY );
glEnableClientState( GL_TEXTURE_COORD_ARRAY );

glEnableClientState( GL_NORMAL_ARRAY );

glVertexPointer( 3, GL_FLOAT, 0, geomVertices);

glNormalPointer( GL_FLOAT, 0, geomNormals);

glTexCoordPointer( 2, GL_FLOAT, 0, geomTexCoords);
glDrawArrays(GL_QUADS,0, geomVertexCount);
glDisableClientState( GL_VERTEX_ARRAY );
glDisableClientState( GL_TEXTURE_COORD_ARRAY );

glDisableClientState( GL_NORMAL_ARRAY );

background image

Ćwiczenie

Ćwiczenie

Zmodyfikuj program z poprzedniego ćwiczenia dodając definicje
wektorów normalnych ścian. Usuń instrukcję włączającą śledzenie

kolorów przez ściany: glEnable(GL_COLOR_MATERIAL). Dla
każdej ściany podaj inną normalną (wszystkie wierzchołki danej

ściany powinny mieć taką samą normalną). Włącz cieniowanie
gładkie. Co zauważyłeś ?

background image

Zaawansowane cieniowanie (7)

Zaawansowane cieniowanie (7)

Jak można zauważyć w ćwiczeniu, pomimo tego, że

włączone jest cieniowanie gładkie, każda ściana

w dowolnym miejscu dostaje tyle samo światła.

Wynika to z faktu, że normalna jest zdefiniowana dla

całej ściany, a zatem ilość światła padającego jest

obliczana na całej ścianie tak samo (światło znajduje

się w nieskończoności za obserwatorem).

Aby poprawić jakość cieniowania należy zdefiniować

inną normalną dla każdego wierzchołka.

background image

Zaawansowane cieniowanie (8)

Zaawansowane cieniowanie (8)

Matematycznie nie istnieje coś takiego jak normalna

wierzchołka!

W praktyce stosujemy znormalizowaną średnią

arytmetyczną normalnych wszystkich ścian

spotykających się w danym wierzchołku.

background image

Ćwiczenie

Ćwiczenie

Zmodyfikuj poprzednie ćwiczenie definiując teraz

normalną dla każdego wierzchołka, jako średnią

arytmetyczną normalnych sąsiadujących ścian.

background image

Zaawansowane cieniowanie (9)

Zaawansowane cieniowanie (9)

Zbiór parametrów optycznych rysowanej ściany, które są
wykorzystywane we wzorze modelu oświetlenia nazywamy

materiałem.

W skład materiału wchodzą następujące parametry:

Ambient – określa w jakim stopniu odbijane jest światło otoczenia

Diffuse – określa w jakim stopniu odbijane jest światło
rozproszone

Specular – określa w jakim stopniu występują odbicia lustrzane

Emmision – określa emitowane światło

Shininess – określa połyskliwość ściany

background image

Zaawansowane cieniowanie (10)

Zaawansowane cieniowanie (10)

Aby ustawić parametry ambient, dissuse, specular i

emission stosujemy procedurę:

void glMaterialfv( GLenum face, Glenum pname, const

GLfloat *param );

face – określa której strony ściany dotyczy ustawiany
parametr – GL_FRONT, GL_BACK,

GL_FRONT_AND_BACK.

background image

Zaawansowane cieniowanie (11)

Zaawansowane cieniowanie (11)

pname – modyfikowany parametr materiału:

GL_AMBIENT

GL_DIFFUSE

GL_SPECULAR

GL_EMISSION

GL_AMBIENT_AND_DIFFUSE

param – wskaźnik na tablicę 4 liczb typu Glfloat
z przedziału <0,1>, które definiują kolejno wpływ własności

materiału na składowe światła: czerwoną, zieloną, niebieską
i alfa.

background image

Zaawansowane cieniowanie (12)

Zaawansowane cieniowanie (12)

Parametr shininess można zmienić za pomocą

procedury:

void glMaterialf( GLenum face, Glenum pname, const

GLfloat param );

face – tak samo jak dla glMaterialfv

pname – musi być GL_SHININESS

param – wartość wykładnika phonga (czyli połyskliwość

materiału)

background image

Ćwiczenie 1

Ćwiczenie 1

Zmodyfikuj procedurę rysującą sześcian tak, aby ustalić

wektory normalne dla każdego wierzchołka. Ustaw

następujące parametry materiału:

ambient i emmision {0,0,0,1}

diffuse {0.7,0.5,0.5,1}

specular {0.5,0.5,0.5,1}

shininess 50

Zastanów się, dlaczego odbicie lustrzane można

zobaczyć tylko w sytuacji, gdy wierzchołek sześcianu jest

skierowany na obserwatora. Poeksperymentuj trochę z

parametrami materiału.

background image

Ćwiczenie 2 (1)

Ćwiczenie 2 (1)

Przekopiuj poniższy kod i wykonaj procedurę initWall

w funkcji main().

//Zadeklaruj globalnie

float *geomVertices;

float *geomTexCoords;

float *geomNormals;

int geomVertexCount;

void quad(int subdiv,int i1, int i2, float x, float y, float back, float nx,

float ny, float s,float t,int pos){

geomVertices[i1*subdiv*3*4+i2*3*4+0+pos*3]=x;

geomVertices[i1*subdiv*3*4+i2*3*4+1+pos*3]=y;

geomVertices[i1*subdiv*3*4+i2*3*4+2+pos*3]=-back;

geomNormals[i1*subdiv*3*4+i2*3*4+0+pos*3]=nx;

geomNormals[i1*subdiv*3*4+i2*3*4+1+pos*3]=ny;

geomNormals[i1*subdiv*3*4+i2*3*4+2+pos*3]=-1.0/3;

geomTexCoords[i1*subdiv*2*4+i2*2*4+0+pos*2]=s;

geomTexCoords[i1*subdiv*2*4+i2*2*4+1+pos*2]=t;

}

void initWall() {

int subdiv=100; float back=1;

float dn=(2.0/3)/subdiv;

float nx=-1.0/3; float ny=-1.0/3;

float s=0; float t=0;

float dst=1.0/subdiv;

float x=-back; float y=-back;

float dp=(float)2*back/subdiv;

glEnable(GL_NORMALIZE);

geomVertices=new float[4*3*subdiv*subdiv];geomTexCoords=new float[4*2*subdiv*subdiv];

geomNormals=new float[4*3*subdiv*subdiv];geomVertexCount=4*subdiv*subdiv;

for (int i1=0;i1<subdiv;i1++) {

for (int i2=0;i2<subdiv;i2++) {

quad(subdiv,i1,i2,x,y,back,nx,ny,s,t,0);

quad(subdiv,i1,i2,x+dp,y,back,nx+dn,ny,s+dst,t,1);

quad(subdiv,i1,i2,x+dp,y+dp,back,nx+dn,ny+dn,s+dst,t+dst,2);

quad(subdiv,i1,i2,x,y+dp,back,nx,ny+dn,s,t+dst,3);

nx+=dn;x+=dp;s+=dst;

}

nx=-1.0/3;x=-back;s=0;

ny+=dn;y+=dp;t+=dst;

}

}

background image

Ćwiczenie 2 (2)

Ćwiczenie 2 (2)

Przekopiuj poniższą procedurę:

void wall() {

glEnableClientState(GL_VERTEX_ARRAY);

glEnableClientState(GL_NORMAL_ARRAY);

glEnableClientState(GL_TEXTURE_COORD_ARRAY);

glVertexPointer(3,GL_FLOAT,0,geomVertices);

glNormalPointer(GL_FLOAT,0,geomNormals);

glTexCoordPointer(2,GL_FLOAT,0,geomTexCoords);

glDrawArrays(GL_QUADS,0,geomVertexCount);

glDisableClientState(GL_VERTEX_ARRAY);

glDisableClientState(GL_NORMAL_ARRAY);

glDisableClientState(GL_TEXTURE_COORD_ARRAY);

}

Zastąp kod rysujący sześcian w displayFrame,

następującymi poleceniami:

glPushMatrix();

wall();

glRotatef(90,1,0,0);

wall();

glRotatef(90,1,0,0);

wall();

glRotatef(90,1,0,0);

wall();

glRotatef(90,1,0,0);

glRotatef(90,0,1,0);

wall();

glRotatef(180,0,1,0);

wall();

glPopMatrix();

background image

Ćwiczenie 2 (cd)

Ćwiczenie 2 (cd)

Zobacz, czy teraz odbicia lustrzane są lepiej rysowane.

Dlaczego ?

background image

Zaawansowane cieniowanie (13)

Zaawansowane cieniowanie (13)

Domyślnym ustawieniem światła jest białe światło

umieszczone w nieskończoności za obserwatorem.

W zależności od implementacji OpenGL można

używać różnej liczby świateł.

Maksymalną liczbę świateł określa stała

GL_MAX_LIGHTS.

Parametry świateł, takie jak: kolor, natężenie, pozycja i

typ można zmodyfikować za pomocą procedur glLightf

i glLightfv.

background image

Zaawansowane cieniowanie (14)

Zaawansowane cieniowanie (14)

void glLightfv( GLenum light, GLenum pname,
const GLfloat *params );

light – stała określająca numer światła –

GL_LIGHTn.

pname – w celu określenia

charakterystyki światła pname przyjmuje
wartości GL_AMBIENT, GL_DIFFUSE
i GL_SPECULAR, wówczas params jest
wektorem czterech liczb (RGBA),
określających kolor danego rodzaju
światła.

background image

Zaawansowane cieniowanie (15)

Zaawansowane cieniowanie (15)

Punktowe źródło światła:

Aby określić położenie światła, również

wykorzystywane jest polecenie glLightfv.

Jako pname należy tutaj podać GL_POSITION, a

jako param podajemy wektor 4 (x,y,z,w) liczb

określających położenie światła we
współrzędnych homogenicznych.

Współrzędne światła są przekształcane przez

macierz model - widok (są traktowane jak punkt w
przestrzeni obiektu) i zapamiętywane w

przestrzeni oka.

Jeżeli wartość w wektora położenia jest równa zero,

to pozostałe wartości są traktowane jako wektor

określający kierunek światła, a samo światło jest
umieszczane w nieskończoności wzdłuż wektora.

background image

Zaawansowanie cieniowanie (16)

Zaawansowanie cieniowanie (16)

Jasność punktowego źródła światła może maleć wraz

z odległością.

Matematycznie jest to wyrażone przez współczynnik:

umieszczony przed jasnością światła w modelu oświetlenia.

Parametry k

c

, k

l

i k

q

można ustawić za pomocą

procedury glLightf podając jako pname odpowiednio

GL_CONSTANT_ATTENUATION,
GL_LINEAR_ATTENUATION i

GL_QUADRATIC_ATTENUATION, a odpowiednią
wartość jako param

background image

Ćwiczenie

Ćwiczenie

Umieść w procedurze rysującej, przed rysowaniem

sześcianu z poprzedniego ćwiczenia następujące

instrukcje:

float

lightPos[]={0,0,-1,0};

glLightfv(GL_LIGHT0,GL_POSITION,lightPos);

Poobracaj trochę tym sześcianem i zaobserwuj różnicę w

zachowaniu oświetlenia w stosunku do poprzedniego

ćwiczenia. Zastanów się jak można wytłumaczyć to, że

światło się obraca wraz

z sześcianem, oraz to, że mimo tego odbicie lustrzane
pozostaje w miejscu.

background image

Zaawansowane cieniowanie (17)

Zaawansowane cieniowanie (17)

Stożkowe źródło światła:

Punktowe źródło światła, ale światło nie rozchodzi się w

każdym kierunku jednakowo.

background image

Zaawansowane cieniowanie (18)

Zaawansowane cieniowanie (18)

Kierunek stożka określa się za pomocą procedury

glLightfv podając jako pname

GL_SPOT_DIRECTION,
a wektor reprezentujący kierunek jako param (we

współrzędnych homogenicznych).

Połowę kąta rozwarcia stożka określa się za pomocą

procedury glLightf podając jako pname

GL_SPOT_CUTOFF, a jako param liczbę z zakresu
<0,90> lub 180 (co oznacza, światło punktowe)

Stopień skupienia światła w stożku określa się za

pomocą procedury glLightf podając jako pname

GL_SPOT_EXPONENT, a jako param liczbę z
zakresu <0,128>. Im większa wartość tym większe

skupienie, 0 oznacza równomierne rozmieszczenie
światła.

background image

Ćwiczenie

Ćwiczenie

Usuń linijki kodu ustawiające pozycję światła dodane w poprzednim
ćwiczeniu. Ustaw właściwości materiału sześcianu tak, aby nie dawał on
odbić lustrzanych. Do części inicjującej, zaraz po załadowaniu do
macierzy model-widok macierzy widoku, dodaj kod ustawiający źródło
światła stożkowego GL_LIGHT0 w pozycji <0,0,6,1>, o kącie rozwarcia
20 stopni (GL_SPOT_CUTOFF – 10), skierowane w kierunku <0,0,-1,0>.
Uruchom program, zaobserwuj efekt działania oświetlenia. Następnie
dodaj linijkę ustawiającą skupienie światła na maksimum
(GL_SPOT_EXPONENT – 128) i znowu uruchom program.

background image

Zaawansowane cieniowanie (19)

Zaawansowane cieniowanie (19)

Za pomocą procedur glLightModelf()

i glLightModelfv() można modyfikować pewne

dodatkowe parametry modelu oświetlenia. Tutaj

przeanalizujemy tylko jeden z nich.

Za pomocą glLightModelfv() można na przykład

zmienić rozproszone światło otoczenia (ambient).

glLightModelfv(GL_LIGHT_MODEL_AMBIENT, params),
gdzie params, to wektor czterech liczb (RGBA)

określających kolor światła otoczenia.

background image

Ćwiczenie

Ćwiczenie

Do wyniku poprzedniego ćwiczenia, w części inicjującej,

dodaj linijkę ustawiającą światło otoczenia na <1,1,1,1>

i zmodyfikuj materiał sześcianu tak, aby odbijał światło

otoczenia następująco <0.1,0.1,0.1,1>.


Document Outline


Wyszukiwarka

Podobne podstrony:
Open GL Pierwszy program
OPEN GL pracownia 1
Open GL pomoc Zapis
kurs open gl
Open GL Pierwszy program
Podstawowe zasady udzielania pomocy przedlekarskiej rany i krwotoki
Farmakologia pokazy, Podstawy Farmakologii Ogólnej (W1)
Podstawy fizyczne
CZLOWIEK I CHOROBA – PODSTAWOWE REAKCJE NA
Podstawy elektroniki i miernictwa2
podstawy konkurencyjnosci
KOROZJA PODSTAWY TEORETYCZNE I SPOSOBY ZAPOBIEGANIA
PODSTAWOWE ZABIEGI RESUSCYTACYJNE (BLS) U DZIECI
01 E CELE PODSTAWYid 3061 ppt

więcej podobnych podstron