gk sprawko lab4 w szachownice wook, Studia, WAT Informatyka, s3 - GK - grafika komputerowa, LAB4


WOJSKOWA AKADEMIA TECHNICZNA

IM. JAROSŁAWA DĄBROWSKIEGO

LABORATORIUM GRAFIKI KOMPUTEROWEJ

SPRAWOZDANIE Z ĆWICZENIA LABORATORYJNEGO NR 4

Prowadzący : dr inż. Marek Salamon

Sprawozdanie wykonał : Łukasz Kołodziejski

Grupa : I7X3S1

Data wykonania : 07.01.2009

Zestaw zadania : 18

TEMAT : MODELOWANIE OŚWIETLENIA

1. Treść zadania

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

  1. Typ obiektu: walec o zmiennej parzystej liczbie podziałów pionowych i poziomych,

  2. Właściwości materiału 1: brązowy błyszczący (widziany w białym świetle),

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

  4. Sposób przyporządkowywania materiałów do obiektu zgodnie ze wzorem: szachownica z uwzględnieniem podziałów pionowych i poziomych.

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

Źródło nr 1:

Źródło nr 2:

Program powinien umożliwiać:

    1. interaktywne, niezależne włączanie i wyłączanie źródeł światła;

    2. interaktywną zmianę liczby podziałów pionowych i poziomych bryły;

    3. interaktywną zmianę wielkości bryły;

    4. interaktywną zmianę położenia obserwatora poprzez podanie następujących parametrów:

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

- 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.

2. Sposób wykonania zadania

Zadanie rozpocząłem od zdefiniowania materiałów oraz świateł.

//materialy

const GLfloat ambient_m1[4] = { 0.5, 0.3 , 0, 1 }; // braz blyszczacy

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

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

const GLfloat ambient_m2[4] = { 1, 0, 0, 1 }; // czerw matowy

const GLfloat diffuse_m2[4] = { 1, 0, 0, 1 };

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

//swiatla

const GLfloat ambient_s1[4] = { 1, 1, 1, 1 }; //spot

const GLfloat diffuse_s1[4] = { 1, 1, 1, 1 };

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

GLfloat position_s1[] = { 5, 0, 0, 1 };

GLfloat direction_s1[] = { -90, 0, 0 };

const GLfloat ambient_s2[4] = {0.5, 0, 0.5, 1 }; //kierunkowe

const GLfloat diffuse_s2[4] = {0.8, 0.8, 0.8, 1 };

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

GLfloat position_s2[] = { 10, 10, 10, 0 };

Składowe materiału pierwszego mają w nazwie końcówkę _m1 , materiału drugiego _m2 oraz świateł kolejno _s1 i s_2. Zapis ten jest dla mnie bardziej czytelny niż zapis w tablicy dwuwymiarowej, więc się nim posłużyłem. Składowe parametru ambient określa w jakim stopniu obiekt odbija światło otoczenia. Diffuse określa jaka ilość światła padającego na obiekt ulega na jego powierzchni rozproszeniu, natomiast specular - określa jaka ilość światła odbija się w sposób lustrzany. Aby uzyskać opowiedni rezultat , w materiale pierwszym należało ustawić małe wartości diffuse, a większe specular - dzięki temu otrzymujemy błyszczący materiał (dla drugiego materiału odwotnie). Również składowe świateł wymagają wytłumaczenia. Otóż position służy do określenia pozycji światła w przestrzeni, a direction to kierunek w jakim świeci światło. Jak w załączonym kodzie widać, wszelkie parametry są ustawione zgodnie z poleceniem zadania.

Następnie napisałem funkcje, które ustawiają materiały i światła według naszych wartości :

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,10);

}

void Material2() {

glMaterialfv(GL_FRONT, GL_AMBIENT, ambient_m2);

glMaterialfv(GL_FRONT, GL_DIFFUSE, diffuse_m2);

glMaterialfv(GL_FRONT, GL_SPECULAR, specular_m2);

}

void Swiatlo1() {

glPushMatrix();

glEnable(GL_LIGHTING);

glRotatef(kat_y, 1, 0, 0);

glRotatef(kat_x, 0, 1, 0);

glRotatef(kat_z, 0, 0, 1);

glTranslatef(R_L1, 0, 0); // R_L1 - odległość od środka

glPushMatrix();

glutWireSphere(0.25, 20, 20); //światło jako kula

glPopMatrix();

glLightfv(GL_LIGHT1, GL_DIFFUSE, diffuse_s1);

glLightfv(GL_LIGHT1, GL_SPECULAR, specular_s1);

glLightfv(GL_LIGHT1, GL_POSITION, position_s1);

glLightf(GL_LIGHT1, GL_SPOT_CUTOFF, 25); //kąt odcięcia = 25

glLightfv(GL_LIGHT1, GL_SPOT_DIRECTION, direction_s1);

glPopMatrix();

}

void Swiatlo2() {

glLightfv(GL_LIGHT2, GL_DIFFUSE, diffuse_s2);

glLightfv(GL_LIGHT2, GL_SPECULAR, specular_s2);

glLightfv(GL_LIGHT2, GL_POSITION, position_s2);

}

GL_SHININESS określa w jakim stopniu ką, pod jakim obserwator widzi powierzchnię , musi być zgodny z kątem lustrzanego odbicia od niej promieni świetlnych , aby widoczny był efekt odblysku. Duże warości zawężają obszar występowania odbłysku, natomiast im mniejsza wartość , tym realistyczniejszy efekt można otrzymać. Wartość 0 sprawia, że zjawisko zachodzi zawsze, niezależnie od kąta obserwacji i kąta padania promieni światła. GL_SPOT_CUTOFF określa kąt odcięcia światła pozycyjnego. Światło rozprzestrzenia się w stożku o kącie rozwartym równym 2*GL_SPOT_CUTOF. Domyślną wartością, jest 180, co oznacza, że światło równomiernie rozhodzi się we wszystkch kierunkach.

Kolejnym etapem było stworzenie walca ze wzrem szachownicy. Funkcja realizująca to zadanie:

void RysujWalec(double h, double r, int nv, int nh)

{

double dH, dAlfa;

int i, j,parzystosc=0;

// Wyznaczenie kata wyznaczajacego pojedynczy wycinek pionowy

dAlfa = 360.0L/(double)nh;

// Wyznaczenie wysokosci pojedynczego wycinka poziomego

dH = h/(double)nv;

// Wyznaczanie wierzcholkow i wektorow normalnych powierzchni bocznych

for (i = 0; floor((i+1)*dH*1.0E10) <= floor(h*1.0E10); i++)

{

if (i%2 == 1) {

parzystosc = 1;

} else

parzystosc = 0;

glBegin(GL_TRIANGLE_STRIP);

glNormal3f(0.0, 0.0, 1.0);

glVertex3f(0.0, (i + 1)*dH, r);

glVertex3f(0.0, i*dH, r);

for (j = 1; j*dAlfa <= 360.0L + dAlfa; j++)

{

if (parzystosc%2 == 0) {

Material1();

parzystosc = 1;

} else {

Material2();

parzystosc = 0;

}

glNormal3f(sin(DEG2RAD(j*dAlfa)), 0.0, cos(DEG2RAD(j*dAlfa)));

glVertex3f(r*sin(DEG2RAD(j*dAlfa)), (i + 1)*dH, r*cos(DEG2RAD(j*dAlfa)));

glVertex3f(r*sin(DEG2RAD(j*dAlfa)), i*dH, r*cos(DEG2RAD(j*dAlfa)));

}

glEnd();

}

// Wyznaczenie wierzcholkow i wektorow normalnych dolnej podstawy

glBegin(GL_TRIANGLE_FAN);

glNormal3f(0.0, -1.0, 0.0);

glVertex3f(0.0, 0.0, 0.0);

for (i = 0; i * dAlfa <= 360.0L + dAlfa; i++)

{ if (i%2 == 1) {

Material1();

} else

Material2();

glVertex3f(r*sin(DEG2RAD(i*dAlfa)), 0.0, r*cos(DEG2RAD(i*dAlfa)));

}glEnd();

// Wyznaczenie wierzcholkow i wektorow normalnych gornej podstawy

glBegin(GL_TRIANGLE_FAN);

glNormal3f(0.0, 1.0, 0.0);

glVertex3f(0.0, h, 0.0);

for (i = 0; i * dAlfa <= 360.0L + dAlfa; i++){

if (i%2 == 1) {

Material1();

} else

Material2();

glVertex3f(r*sin(DEG2RAD(i*dAlfa)), h, r*cos(DEG2RAD(i*dAlfa)));

}

glEnd();

Swiatlo1();

Swiatlo2();

}

Funkcja rysuje walec o zadanej wysokości, promieniu oraz liczbie podziałów pionowych i poziomych. Tryb modelowania powierzchni bocznej to GL_TRIANGLE_STRIP , a podstaw to GL_TRIANGLE_FAN. Jak widać funkcja powyżej również konstruuje wektory normalne , dzięki czemu oświetlenie jest generowane prawidłowo. Wektor normalny danej powierzchni to wektor do niej prostopadły. Określa on jej orientację w przestrzeni, w szczególności względem źródła światła i obserwatora. Na jego podstawie można wyznaczyć ilość światła jaka dociera do powierzchni i ilość, która w kierunku obserwatora jest od niej odbijana. W OpenGL obliczenia związane z oświetleniem wkonywane są dla wierzchołków.

Program zawiera również możliwość zmiany parametrów podanych w zadaniu. Odpowiada za to funkja :

void ObslugaKlawiatury(unsigned char klawisz, int x, int y)

{

switch(klawisz)

{

//obserwator

case '+': OBSERWATOR_ODLEGLOSC++;

break;

case '-': OBSERWATOR_ODLEGLOSC--;

break;

case 'S': OBSERWATOR_WYSOKOSC++;

break;

case 's': OBSERWATOR_WYSOKOSC--;

break;

case 'a': OBSERWATOR_OBROT_Y++;

break;

case 'd': OBSERWATOR_OBROT_Y--;

break;

//podzial walca (lPionowych - to liczba podziałów w pionie itd.)

case '2':

lPionowych = (lPionowych == LPION_MAX)? LPION_MAX : lPionowych + 2;

break;

case '@':

lPionowych = (lPionowych == LPION_MIN)? LPION_MIN : lPionowych - 2;

break;

case '1':

lPoziomych = (lPoziomych == LPOZ_MAX)? LPOZ_MAX : lPoziomych + 2;

break;

case '!':

lPoziomych = (lPoziomych == LPOZ_MIN)? LPOZ_MIN : lPoziomych - 2;

break;

//wysokosc walca

case 'w':

wysokosc = (wysokosc == WYS_MAX) ? WYS_MAX : wysokosc + 1;

break;

case 'W':

wysokosc = (wysokosc == 1) ? wysokosc : wysokosc - 1;

break;

//promien walca

case 'p':

promien = (promien == R_MAX) ? R_MAX : promien + 1;

break;

case 'P':

promien = (promien == 1) ? promien : promien - 1;

break;

//reset

case 'r':

UstawDomyslneWartosciParametrow();

break;

case 'm':

menu = (menu == ID_MENU_SWIATLA) ? ID_MENU_MATERIALU : ID_MENU_SWIATLA;

break;

//predkosc kątowa źródła nr 1

case '3':

if(roznica<2) roznica=roznica+0.5;

break;

case '#' :

if(roznica>0.5) roznica=roznica-0.5;

break;

//kat nachyenia orbity do osi OX

case '7':

kat_y+=0.5;

break;

case '&':

kat_y-=0.5;

break;

//wlaczenie / wylaczenie swiatel

case '4': glEnable(GL_LIGHT1);

break;

case '$': glDisable(GL_LIGHT1);

break;

case '5': glEnable(GL_LIGHT2);

break;

case '%': glDisable(GL_LIGHT2);

break;

//promien orbity źródła nr 1

case '8': R_L1++;

break;

case '*': R_L1--;

break;

if (menu == ID_MENU_SWIATLA)

UstawParametryOswietlenia(sIndeks, klawisz);

else

UstawParametryMaterialu(mIndeks, klawisz);

break;

// Wcisniecie klawisza ESC powoduje wyjscie z programu

case 27:

exit(0);

}

}

Jak widać ,dzięki odpowiednim klawiszom możemy zmieniać interesujące nas wartości. W kodzie starałem się umieścić rozsądne komentarze, aby rozpoznać który klawisz odpowiada za jaką funkcję.

3. UZYSKANE WYNIKI

0x01 graphic
0x01 graphic

0x01 graphic
0x01 graphic

Jak widać na załączonych obrazkach w programie istnieje możliwość zmiany wszelkich parametrów, takich jak wysokość, promień -zaróno walca jak i źródła światła, oraz liczby podziałów pionowych i poziomych walca.

4. WNIOSKI

Zadanie laboratoryjne zostało zrealizowane. Cel zapoznania się z modelowaniem oświetlenia za pomocą biblioteki OpenGL został osiągnięty. Dobierając odpowiednie wartości dla materiałów jak i źródeł światła, zaoberwowałem wiele efektów. Otóż same zmiany były łatwe do wykonania i wystarczyło tylko dobierać wartości, aby uzyskać oczekiwane wyniki. Zwróciłem też uwagę, że przy dużej liczbie podziałów walca oraz przy włączonym świetle, program potrafi zwolnić swoje działanie. Co prawda uzyskane efekty są o wiele ładniejsze, aczkolwiek problem z klatkowaniem obrazu zmniejsza ochotę oglądania takich wyników. Jednakże praca laboratoryjna była ciekawa , a efekty ukazywały ogromne możliwości OpenGL'a.



Wyszukiwarka