sprawozdanie l4 albin doc


WOJSKOWA AKADEMIA TECHNICZNA

LABORATORIUM Z

GRAFIKI KOMPUTEROWEJ

SPRAWOZDANIE

Z ĆWICZENIA 4

Temat: Modelowanie oświetlenia.

Wykonał: Albin Sadowski

Grupa: I9X6S1

Prowadzący: mgr inż. Wojciech Sulej

Data: 17.01.2011 r.1. Cel ćwiczenia

Zadanie 3

Wykorzystując biblioteki OpenGL i GLUT napisać program przedstawiający perspektywistyczny obraz obiektu o następujących parametrach:

1. Typ obiektu: ½ elipsoidy o stosunku osi 2:3:5 ciętej wzdłuż osi najdłuższej zmiennej parzystej liczbie podziałów pionowych i poziomych,

2. Właściwości materiału nr 1: zielony matowy (widziany w białym świetle),

3. Właściwości materiału nr 2: fioletowy błyszczący (widziany w białym świetle),

4. Sposób przyporządkowania materiałów do obiektu zgodnie ze wzorem: pasy poziome względem osi najdłuższej z uwzględnieniem podziałów poziomych.

Obiekt należy oświetlić dwoma źródłami światłą o następujących parametrach:

  1. Światło białe sceny (włączenie/wyłączenie)

  2. Źródło nr 1:

- typ: reflektor (ang. spot)

- kolor: czerwony,

- Natężenie: 1,

- kąt odcięcia: 300

- położenie: zmienne po orbicie kołowej o środku w punkcie S(0,0,0) z możliwością interaktywne

zmiany następujących parametrów:

- promienia orbity,

- kąta nachylenia orbity do osi OX,

- kąta nachylenia orbity do osi OZ,

- kierunek świecenia: na obiekt.

3) Źródło nr 2:

- typ: kierunkowe

- kolor: żółty

- natężenie: 0.7

- położenie: stałe w punkcie P(-10, 10, 10) układu współrzędnych sceny.

- kierunek świecenia: na obiekt

Program powinien umożliwić interaktywne, niezależne włączenie i wyłączanie źródeł światła.

Należy również zapewnić użytkownikowi możliwość zmiany położenia obserwator poprzez podanie następujących parametrów:

- odległości obserwatora od środka układu współrzędnych sceny,

- wysokości względem płaszczyzny XZ,

- kąta obrotu wokół osi OY w zakresie [00, 3600] z krokiem 10.

Oświetlony obiekt powinien zawsze znajdować się w centralnej części okna.

W programie uwzględnić możliwość interakcyjnej zmiany położenia obserwatora poprzez podanie następujących parametrów:

1. Odległości obserwatora od obiektu,

2. Wysokości obserwatora względem płaszczyzny, na której położony jest obiekt,

3. Kąta obrotu wokół obiektu w zakresie [0, 360] z krokiem 1.

UWAGA: Obserwator jest zawsze zwrócony przodem w kierunku obiektu.

2. Sposób rozwiązania zadania

Zadanie należało rozpocząć od zamodelowania elipsoidy. W tym celu należało zastosować współrzędne sferyczne:

0x01 graphic

W pierwszej pętli następuje przejście od 0 do KATb - 0.01 (- 0.01 ze względu na błąd
w przybliżenia liczb typu float), następnie w zagnieżdżonej pętli od j = 0 do KATa - 0.01 znajdują
się instrukcje odpowiedzialne za wyznaczanie czterech punktów, które będą łączone.

Wyznaczone punkty należało podać w odpowiedniej kolejności by zostały dobrze połączone w trybie GL_QUADS. Dodatkowo dla każdego wierzchołka należało wyznaczyć wektor normalny przy pomocy funkcji glNormal3f().

for (i = 0; i <= KATb - 0.01; i = i + KATb/(nh))

{

for (j = 0.0; j <= KATa - 0.01; j = j + (KATa/nv))

{

x = A*cos(j*M_PI/180)*sin(i*M_PI/180);

y = C*cos(i*M_PI/180);

z = B*sin(j*M_PI/180)*sin(i*M_PI/180);

tmpj = j + (KATa/nv);

tmpi = i + (KATb/(nh));

tmpx = A*cos(tmpj*M_PI/180)*sin(i*M_PI/180);

tmpy = C*cos(i*M_PI/180);

tmpz = B*sin(tmpj*M_PI/180)*sin(i*M_PI/180);

kolex = A*cos(j*M_PI/180)*sin(tmpi*M_PI/180);

koley = C*cos(tmpi*M_PI/180);

kolez = B*sin(j*M_PI/180)*sin(tmpi*M_PI/180);

koletmpx = A*cos(tmpj*M_PI/180)*sin(tmpi*M_PI/180);

koletmpy = C*cos(tmpi*M_PI/180);

koletmpz = B*sin(tmpj*M_PI/180)*sin(tmpi*M_PI/180);

glBegin(GL_QUADS);

glNormal3f(tmpx, tmpy, tmpz);

glVertex3f(tmpx, tmpy, tmpz);

glNormal3f(x, y, z);

glVertex3f(x, y, z);

glNormal3f(kolex, koley, kolez);

glVertex3f(kolex, koley, kolez);

glNormal3f(koletmpx, koletmpy, koletmpz);

glVertex3f(koletmpx, koletmpy, koletmpz);

glEnd();

}

}

Z tego względu, że jest to ½ elipsoidy trzeba było wyrysować ściany boczne ścięcia bryły.
Ze względu na położenie tej ściany bocznej, każdy punkt powinien posiadać wektor normalny prostopadły do tej ściany, który jest równy glNormal3f(0, 0, -1).

// pierwsza sciana boczna

if (j == 0)

{

glBegin(GL_QUADS);

glNormal3f(0, y, -1);

glVertex3f(0, y, 0);

glNormal3f(0, y, -1);

glVertex3f(x, y, z);

glNormal3f(0, koley, -1);

glVertex3f(kolex, koley, kolez);

glNormal3f(0, koley, -1);

glVertex3f(0, koley, 0);

glEnd();

}

// druga sciana boczna

glBegin(GL_QUADS);

glNormal3f(0, tmpy, -1);

glVertex3f(0, tmpy, 0);

glNormal3f(0, tmpy, -1);

glVertex3f(tmpx, tmpy, tmpz);

glNormal3f(0, koletmpy, -1);

glVertex3f(koletmpx, koletmpy, koletmpz);

glNormal3f(0, koletmpy, -1);

glVertex3f(0, koletmpy, 0);

glEnd();

Rys. 1 Rys. 2

0x01 graphic
0x01 graphic

Rys. 1, 2. Narysowana ½ elipsoidy.

3. Ustawienie odpowiedniego materiału

W celu zaprojektowanie odpowiedniego materiału należało wpierw się zapoznać
z właściwościami funkcji tj. ambient, diffuse, specular jak również sprawdzić przy jakim zmieszaniu barw RGB możemy otrzymać poszukiwany kolor. Po wykonaniu tego zabiegu otrzymałem taki kod:

GLfloat ambient_m1[4] = {0, 0, 0, 1}; // zielony matowy

GLfloat diffuse_m1[4] = {0, 1, 0, 1};

GLfloat specular_m1[4] = {0, 0, 0, 1};

GLfloat ambient_m2[4] = {0.5, 0.0, 0.5, 1}; // fioletowy błyszczący

GLfloat diffuse_m2[4] = {0.5, 0.0, 0.5, 1};

GLfloat specular_m2[4] = {0.5, 0, 0.5, 1};

Po przypisaniu zmiennym odpowiednich parametrów należało napisać funkcje, które będą ładowały konkretne parametry i tym sposobem tworzyły odpowiedni materiał, będący pokryciem bryły.

void Material1() {

glMaterialfv(GL_FRONT, GL_AMBIENT, ambient_m1);

glMaterialfv(GL_FRONT, GL_DIFFUSE, diffuse_m1);

glMaterialfv(GL_FRONT, GL_SPECULAR, specular_m1);

glMaterialf(GL_FRONT, GL_SHININESS,0);

}

void Material2() {

glMaterialfv(GL_FRONT, GL_AMBIENT, ambient_m2);

glMaterialfv(GL_FRONT, GL_DIFFUSE, diffuse_m2);

glMaterialfv(GL_FRONT, GL_SPECULAR, specular_m2);

glMaterialf(GL_FRONT, GL_SHININESS, 128);

}

Materiał 2 miał być błyszczący więc należało dopisać parametr i odpowiednio ustawić, który jest odpowiedzialny za błyszczenie materiału (GL_SHININESS).

Kolejnym krokiem związanym z wyświetlaniem materiału było napisanie funkcji, która na zmianę będzie wybierała jeden z nich.

void kolorowanie(int i)

{

switch(i)

{

case 0:

Material1();

break;

case 1:

Material2();

break;

}

}

Teraz należało napisać ciąg instrukcji przed każdym wyrysowaniem czworokąta w trakcie rysowania elipsoidy, które umożliwiają wywołanie funkcji o odpowiednim argumencie do nakładania materiału na bryłę.

kolorowanie(kolor);

kolor++;

if (kolor == 2)

kolor = 0;

0x01 graphic

Rys. 3. Bryła z odpowiednio nałożonymi materiałami.

4. Modelowanie oświetlenia

Modelowanie oświetlenie podobnie jak w przypadku modelowania materiału należało wpierw zaznajomić się z funkcjami, które są odpowiedzialne za otoczenie światła, rozproszenie, lustrzane odbicie, położenie, kierunek świecenia, tłumienie kątowe, stałe tłumienie, tłumienie liniowe i tłumienie kwadratowe.

GLfloat param_swiatla1[10][4] = {

{0.0, 0, 0, 1.0}, // [0] otoczenie

{1.0, 0.0, 0.0, 1.0}, // [1] rozproszenie

{1.0, 0, 0, 1.0}, // [2] lustrzane

{0.0, 0.0, 1.0, 1.0}, // [3] polozenie

{0.0, 0.0, -1.0, 0.0}, // [4] kierunek swiecenia

{0.0, 0.0, 0.0, 0.0}, // [5] tlumienie katowe swiatla

{30.0, 0.0, 0.0, 0.0},// [6] kat odciecia swiatla

{1.0, 0.0, 0.0, 0.0}, // [7] stale tlumienie

{0.0, 0.0, 0.0, 0.0}, // [8] tlumienie liniowe

{0.0, 0.0, 0.0, 0.0}}; // [9] tlumienie kwadratowe

GLfloat param_swiatla2[5][4] = {

{0.0, 0.0, 0.0, 0.0}, // [0] otoczenie

{1.0, 1.0, 0, 0.7}, // [1] rozproszenie

{1.0, 1.0, 0, 7 }, // [2] lustrzane

{-10, 10, 10, 0}, // [3] polozenie

{0.0, 0.0, -1.0, 0.0}, // [4] kierunek swiecenia

};}

Następnie zostały te właściwości przekopiowane do tablic:

memcpy(swiatlo1, param_swiatla1, LPOZ_MENU_SWIATLA*4*sizeof(GLfloat));

memcpy(swiatlo2, param_swiatla2, LPOZ_MENU_SWIATLA*4*sizeof(GLfloat));

Kolejnym krokiem było napisanie funkcji, które będą odpowiednie do wyświetlania poszczególnych świateł. Dla źródła światła nr 1:

void Swiatlo1Reflektor()

{

glPushMatrix();

glRotatef(kat_x, 1, 0, 0);

glRotatef(kat_y, 0, 1, 0);

glRotatef(kat_z, 0, 0, 1);

glTranslatef(r_reflektor, 0, 0);

glLightfv(GL_LIGHT1, GL_AMBIENT, swiatlo1[0]);

glLightfv(GL_LIGHT1, GL_DIFFUSE, swiatlo1[1]);

glLightfv(GL_LIGHT1, GL_SPECULAR, swiatlo1[2]);

glLightfv(GL_LIGHT1, GL_POSITION, swiatlo1[3]);

glLightfv(GL_LIGHT1, GL_SPOT_DIRECTION, swiatlo1[4]);

glLightfv(GL_LIGHT1, GL_SPOT_CUTOFF, swiatlo1[5]);

glutWireSphere(0.5, 8, 8);

glPopMatrix();

}

Wpierw następuje odłożenie na stos (glPushMatrix()), kolejno jest ona odpowiednio obracana (glRotatef()), oddalana (glTranslatef()) a w końcu następuje załadowanie parametrów światła przy pomocy odpowiednich funkcji, które przyjmują wybrane argumenty. Dodatkowo jest umieszczona instrukcja za wyrysowanie sfery (glutWireSphere()) by można było zobaczyć, w którym miejscu znajduje się źródło światła.

Rys. 4 Rys. 5

0x01 graphic
0x01 graphic

Rys. 4, 5. Bryła podczas załączonego światła nr 1.

Kolejno funkcja dla źródła światła nr 2:

void Swiatlo2Kierunkowe()

{

glPushMatrix();

glLightfv(GL_LIGHT2, GL_AMBIENT, swiatlo2[0]);

glLightfv(GL_LIGHT2, GL_DIFFUSE, swiatlo2[1]);

glLightfv(GL_LIGHT2, GL_SPECULAR, swiatlo2[2]);

glLightfv(GL_LIGHT2, GL_POSITION, swiatlo2[3]);

glPopMatrix();

}

Jest ona wpierw odkładana na stos, a następnie wykonywane instrukcje odpowiedzialne
za wyświetlenie światła. Zostało to tak zrobione, ponieważ bez względu na zmianę położenia obserwatora to źródło światła będzie zawsze znajdowało się w tym samym miejscu

Rys. 6 Rys. 7

0x01 graphic
0x01 graphic

Rys. 6, 7. Bryła podczas załączonego światła nr 2.

5. Interakcyjna zmiana położenia użytkownika

W programie należało umożliwić interakcyjną zmianę położenia obserwatora. W tym celu zostały napisane takie instrukcje w funkcji WyswietlObraz().

glTranslatef(0, 0, -odleglosc_obs);

glRotatef( (180*(asin(wysokosc_obs/odleglosc_obs))/M_PI), 1, 0, 0);

glRotatef(katY, 0, 1, 0);

glTranslatef(0, -wysokosc_obs, 0);

Pierwsze instrukcja jest odpowiedzialna za ustawienie odpowiedniej odległości obserwatora od obiektu względem osi OZ.

Druga instrukcja odpowiada za zmianę wysokości obserwatora w zależności od odległości
od obiektu. W tym celu wykonuje rotacje o kąt równy arcsin, który jako argument przyjmuje stosunek wysokości do odległości. Funkcja asin() zwraca wartość w radianach, wiec należało przejść
na kąt poprzez pomnożenie wyniku przez 180 i podzielenie przez M_PI.

Instrukcja glRotatef() jest odpowiedzialna za możliwość obrotu wokół obiektu. Ostatni glTranslatef() odpowiada za wysokość obserwatora względem płaszczyzny, na której położony jest obiekt.

6. Obsługa obiektu przez użytkownika

Program miał za zadanie umożliwić użytkownikowi zmiany położenia obserwatora, załączanie świateł, zmienianie liczby podziałów poziomych i pionowych poprzez naciśnięcie odpowiedniego klawisza. Zostały one zrealizowane przy pomocy funkcji ObslugaKlawiatury(), która pobiera wciśnięty klawisz a kolejno sprawdza, czy została mu przypisana konkretna akcja. Oprócz wcześniejszych instrukcji dopisałem kilka innych, które są potrzebne do zrealizowania zadań opisanych we wstępie.

case '-':

katY = katY - 2;

break;

case '=':

katY = katY + 2;

break;

case '[':

odleglosc_obs = odleglosc_obs + 1;

break;

case ']':

odleglosc_obs = odleglosc_obs - 1;

break;

case ';':

wysokosc_obs = wysokosc_obs + 1;

break;

case '\'':

wysokosc_obs = wysokosc_obs - 1;

break;

case 't':

r_reflektor = r_reflektor+1;

break;

case 'T':

r_reflektor = r_reflektor-1;

break;

case 's':

kat_y = kat_y-1;

break;

case 'f':

kat_y = kat_y+1;

break;

case 'z':

kat_x = kat_x+1;

break;

case 'x':

kat_x = kat_x-1;

break;

case 'e':

kat_z = kat_z+1;

break;

case 'd':

kat_z = kat_z-1;

break;

case '8':

wlswiatlo0 = -wlswiatlo0;

if (wlswiatlo0 == 1)

glEnable(GL_LIGHT0);

else

glDisable(GL_LIGHT0);

break;

case '9':

wlswiatlo1 = -wlswiatlo1;

if (wlswiatlo1 == 1)

glEnable(GL_LIGHT1);

else

glDisable(GL_LIGHT1);

break;

case '0':

wlswiatlo2 = -wlswiatlo2;

if (wlswiatlo2 == 1)

glEnable(GL_LIGHT2);

else

glDisable(GL_LIGHT2);

break;

Oprócz zmiany by były tylko parzysta liczba podziałów poziomych i pionowych bryły, ważne były funkcje odpowiedzialne za włączanie świateł, np.:

case '8':

wlswiatlo0 = -wlswiatlo0;

if (wlswiatlo0 == 1)

glEnable(GL_LIGHT0);

else

glDisable(GL_LIGHT0);

break;

Domyślnie zmienna wlswiatlo0 = -1 czyli światło GL_LIGHT0 jest wyłączone. Każde naciśnięcie klawisza „8” zmienia stan zmiennej na przeciwny, więc albo włącza albo wyłącza dane światło.

Rys. 8 Rys. 9

0x01 graphic
0x01 graphic

Rys. 8. Bryła bez załączonych źródeł światła.

Rys. 9. Bryła z załączonymi wszystkimi źródłami światła.

7. Wnioski

Narysowanie ½ elipsoidy i zamodelowanie materiałów i oświetlenia zostało wykonane zgodnie z oczekiwaniami. Ćwiczenie wymagało zapoznanie się z podstawowymi właściwościami atrybutów materiałów i świateł i odpowiednim ich ustawieniu. Dużą rolę odgrywało tutaj poprawne zamodelowanie elipsoidy i wyznaczenie wektorów normalnych jej wierzchołków.

Podczas ćwiczenia laboratoryjnego popełniłem błąd w wyznaczaniu wektorów normalnych ścian bocznych wycięcia bryły, lecz zostały one poprawione w tym sprawozdaniu.

6



Wyszukiwarka

Podobne podstrony:
SPRAWOZDANIE+L4 doc
SPRAWOZDANIE L4
Sprawozdanie1 czemiel halaburda doc
Sprawozdanie Pomiar tempearatury doc
Sprawozdanie z Programowania wsp¢ˆbie¾nego doc
~$ sprawozdanie z promieniowania WM doc
Sprawozdanie 401 ABBEGO DOC
sprawozdanie z elektroniki diody doc
Sprawozdanie6 czemiel halaburda doc
sprawozdanie10 strona tytułowa (2) doc
Sprawozdanie5 czemiel halaburda doc
Sprawozdanie M2 moje doc
Dewiacja sprawozdanie nr 2 (nowe) doc
SPRAWOZDANIE Z ĆWICZENIA NR 4 doc
Sprawozdanie z Technogii Betonu doc

więcej podobnych podstron