background image

'

  SPRAWOZDANIE 

Z LABORATORIUM

 GRAFIKI KOMPUTEROWEJ

Temat: Modelowanie oświetlenia.

wykonał: Piotr Korlaga I0X4S1

data wykonania ćwiczenia: 15.12.2011r.

background image

1. Treść zadania.

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

Typ obiektu: bryła z ćwicz. 2 o zmiennej parzystej liczbie podziałów pionowych i 

poziomych,
2.

Właściwości materiału nr 1: żółty emitujący  (widziany w białym świetle),

3.

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

4.

Sposób przyporządkowania materiałów do obiektu zgodnie ze wzorem: pasy 

pionowe z uwzględnieniem podziałów pionowych.

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

typ: reflektor (ang. spot), 

kolor: fioletowy,

natężenie: 0.9,

kąt odcięcia: 45

o

,

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

interaktywnej zmiany następujących parametrów:
o

promienia orbity,

o

prędkości kątowej (3 różne prędkości),

o

kąta nachylenia orbity do osi OX,

kierunek świecenia: na obiekt.

Źródło nr 2:

typ: kierunkowe,

kolor: zielony,

natężenie: 0.7,

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

kierunek świecenia: na obiekt.

Program powinien umożliwiać:
a) interaktywne, niezależne  włączanie i wyłączanie źródeł światła;
b) interaktywną zmianę liczby podziałów pionowych i poziomych bryły;
c) interaktywną zmianę wielkości bryły;
d) 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 [0

o

, 360

o

]  z krokiem 1

o

.

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

2. Wstęp

W  celu   rozwiązania   tego   zadania   należy   zdefiniować   macierz   parametrów   dla   każdego 

materiału, a następnie zaimplementować przydział kolorów zgodnie z punktem 4. z treści zadania. 
Kolejnym   krokiem   jest   zdefiniowanie   macierzy   dla   parametrów   światła   i   zaimplementowanie 
możliwości ich niezależnego włączania, przy czym dla źródła nr 2 należy dokonać odpowiedniej 
animacji aby wprawić źródło w ruch. Ponadto zależy przewidzieć obsługę klawiatury.

background image

 3. Rozwiązanie

3.1 Zdefiniowanie parametrów materiału i przydział materiałów pasami pionowymi.

3.1.1

Implementacja

     Deklaracja macierzy:

GLfloat material_zolty[5][4]=
{

        {1,1,0,1},
        {1,1,0,1},

        {1,0,1,1},
        {1,0,0,0},

  {0.3,0.3,0.0,1}

};

GLfloat material_zielony[5][4]=

{
        {0,1,0,1}, 

        {0,1,0,1},
        {1,0,1,1},

        {1,0,0,0},

  {0,0,0,0}

};

Funkcje ładujące macierze z parametrami kolorów:

void

 Material_zolty()

{
        glMaterialfv(GL_FRONT, GL_AMBIENT, material_zolty[0]);

        glMaterialfv(GL_FRONT, GL_DIFFUSE, material_zolty[1]);
        glMaterialfv(GL_FRONT, GL_SPECULAR, material_zolty[2]);

        glMaterialfv(GL_FRONT, GL_SHININESS, material_zolty[3]);  

 glMaterialfv(GL_FRONT, GL_EMISSION, material_zolty[4]);

}

void

 Material_zielony()

{

        glMaterialfv(GL_FRONT, GL_AMBIENT, material_zielony[0]);
        glMaterialfv(GL_FRONT, GL_DIFFUSE, material_zielony[1]);

        glMaterialfv(GL_FRONT, GL_SPECULAR, material_zielony[2]);
        glMaterialfv(GL_FRONT, GL_SHININESS, material_zielony[3]);

 glMaterialfv(GL_FRONT, GL_EMISSION, material_zielony[4]);

}

background image

Funkcja rysująca stożek – przydział kolorów

void

 Rysuj(

double

 r)

{

for

(j=0,k=0;(j+4.0/N2<=WYSOKOSC);j+=4.0/N2,k+=4.0/N2)

{

glBegin(GL_QUAD_STRIP);

for

(i=0; i*dAlfa<=180.0; i++)

{

if

 ((

int

)i % 2== 0)    Material_zolty();

              

else

                   Material_zielony();

//TUTAJ ŚCIANA BOCZNA 

}
glEnd();

}

for

(l=0,k=-r;(l+4.0/N2<=WYSOKOSC);l+=4.0/N2,k-=4.0/N2)

{
glBegin(GL_QUAD_STRIP);

for

(a=0,i=k,j=k-4.0/N2;i<=-k &&j<=-k+4.0/N2;i+=dAlfa/100*

(-k),j+=dAlfa/100*(-    k+4.0/N2),zz++)

{
 

if

 ((

int

)a% 2 == 0)    Material_zolty();

        

else

                   Material_zielony();

//TUTAJ ŚCIANA BOCZNA

glEnd();

}

glBegin(GL_QUAD_STRIP); 

for

(i=0; i*dAlfa<=180.0; i++)

{

if

 ((

int

)i% 2 == 0)    Material_zolty();

              

else

  Material_zielony();

           //TUTAJ PODSTAWA DOLNA

}

glEnd();

glBegin(GL_QUAD_STRIP);

for

(i=0; i*dAlfa<=180.0; i++)

{

if

 ((

int

)i% 2 == 0)    Material_zolty();

              

else

                   Material_zielony();

//TUTAJ PODSTAWA GORNA

glEnd();

}

3.1.2

Opis

Powyższe tablice składają się z 5 wierszy, przy czym każdy wiersz określa odpowiedni 
parametr o wartości odpowiadającej składowym RGBA, i tak:

I ambient – współczynnik odbicia światła otoczenia,
II diffuse – współczynnik odbicia światła rozproszonego,
III specular – współczynnik odbicia światła lustrzanego, 
IV shinines – współczynnik połysku, 
V emission – współczynnik światła emitowanego.

background image

              Kolor żółty i zielony został ustwione w parametrach ambient i diffuse. Wartość 
110 odpowiada kolorowi żółtemu, a wartość 010 kolorowi zielonemu w RGB.Dodatkowo 
parametrowi specular przypsałem wartość 1,0,1,1 zgodnie z  kolorem źródła światła, aby 
otrzymać realistyczny efekt. Współczynnik połysku zasugerowany w instrukcji okazał się 
jednak moim zdaniem za duży, ustawiłem go na 1 i nawet taka mała wartość daje ciekawy 
efekt. Aby uzyskać kolor żółty emitujący ustawiłem wartość emission na (0.3,0.3,0.0,1) 
odpowiada to kolorowi żółtemu, większe współczynniki dają już mniej realistyczny efekt.

Następnie stworzyłem funkcję, która ustawia dla każdego parametru odpowiadający jej 
wiersz macierzy za pomocą funkcji 

 glMaterialfv(GL_FRONT, GL_PARAMETR,material[nr 

wiersza]).

 Przydział kolorów zrealizowałem za pomocą instrukcji warunkowej if w pętli 

rysującej każdą scianę. W tym celu ustawiłem dodatkowy licznik a lub i. Gdy licznik jest 
parzysty przydzielany jest kolor żółty, w przeciwnym wypadku zielony.

3.1.3 Efekt

3.2

Ustawienie wektorów normalnych.

3.2.1 Implementacja

void

 Rysuj(

double

 r)

{

 

float

 Rgornej=r+4*r;

glColor3f(0.0,1.0,0.0);

for

(j=0,k=0;(j+4.0/N2<=WYSOKOSC);j+=4.0/N2,k+=4.0/N2)

{

glBegin(GL_QUAD_STRIP);

for

(i=0; i*dAlfa<=180.0; i++)

{

if

 ((

int

)i % 2== 0)    Material_zolty();

        

else

                   Material_zielony();

    glNormal3f((r+k)*cos(DEG2RAD(i*dAlfa)), -(r+k),

(r+k)*sin(DEG2RAD(i*dAlfa)));

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

glVertex3f((r+k+4.0/N2)*cos(DEG2RAD(i*dAlfa)), j+4.0/N2, 

(r+k+4.0/N2)*sin(DEG2RAD(i*dAlfa)));

}
glEnd();

background image

}

for

(l=0,k=-r;(l+4.0/N2<=WYSOKOSC);l+=4.0/N2,k-=4.0/N2)

{

glBegin(GL_QUAD_STRIP);
glNormal3f(0,0,-1);

for

(zz=0,i=k,j=k-4.0/N2;i<=-k &&j<=-k+4.0/N2;i+=dAlfa/100*(-k),j+=dAlfa/100*(-

k+4.0/N2),zz++)

{

if

 ((

int

)zz% 2 == 0)    Material_zolty();

        

else

                   Material_zielony();

glVertex3f(i*cos(DEG2RAD(180)), l, i*sin(DEG2RAD(180)));

glVertex3f(j*cos(DEG2RAD(180)), l+4.0/N2, j*sin(DEG2RAD(180)));

}

glVertex3f(-k*cos(DEG2RAD(180)), l, -k*sin(DEG2RAD(180)));
glVertex3f((-k+4.0/N2)*cos(DEG2RAD(180)), l+4.0/N2, (-

k+4.0/N2)*sin(DEG2RAD(180)));

glEnd();

}

glBegin(GL_QUAD_STRIP); 

glNormal3f(0,1,0);

for

(i=0; i*dAlfa<=180.0; i++)

{

if

 ((

int

)i% 2 == 0)    Material_zolty();

        

else

                   Material_zielony();

glVertex3f(0,l,0);

glVertex3f(-k*cos(DEG2RAD(i*dAlfa)),l,-k*sin(DEG2RAD(i*dAlfa)));

}

glEnd();

glBegin(GL_QUAD_STRIP);
glNormal3f(0,-1,0);

for

(i=0; i*dAlfa<=180.0; i++)

{

if

 ((

int

)i% 2 == 0)    Material_zolty();

        

else

                   Material_zielony();

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

}
glEnd();

}

3.2.2

Opis

Z wyznaczeniem wektorów dla podstawy górnej i dolnej oraz dla ściany bocznej tylniej nie 
ma problemów, bowiem są wektor normalny to wektor prostopadły do ściany, i tak:

Podstawa dolna N=(0,-1,0)
Podstawa górna N=(0,1,0)
Ściana boczna tylna N=(0,0,-1)

background image

Do wyznaczenia wektorów ściany bocznej przedniej zbudujmy równanie stożka:

Następnie wyznaczamy iloczyn wektorowy pochodnych z równania parametrycznego:

Jako że nasz stożek jest odwrócony otrzymujemy wektor normalny o współrzęnych 
odwróconych, czyli:

Funkcja 

glEnable(GL_NORMALIZE) 

odpowiadaja za normalizację wektora.

3.3 Źródło numer 1

3.3.1 Implementacja

Deklaracja macierzy:

GLfloat swiatlo1[10][4]= {
    {0.0, 0.0, 0.0, 0.0},  

    {1.0, 0.0, 1.0, 0.0},  
    {1.0, 0.0, 1.0, 0.0},  

    {0.0, 0.0, 0.0, 1.0},  
    {0.0, 0.0, 1.0, 0.0}, 

    {0.0, 0.0, 0.0, 0.0},  
    {45.0, 0.0, 0.0, 0.0},

    {0.9, 0.0, 0.0, 0.0},  

 

    {0.0, 0.0, 0.0, 0.0},  

    {0.0, 0.0, 0.0, 0.0}};

background image

          

 Funkcje ładujące macierze z parametrami oświetlenia:

void

 WlaczOswietlenie(

void

)

{

  glEnable(GL_LIGHTING);

  

if

(Zrodlo1==1){

  glEnable(GL_LIGHT1);

  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]);

  glLightf(GL_LIGHT1, GL_SPOT_EXPONENT, swiatlo1[5][0]);
  glLightf(GL_LIGHT1, GL_SPOT_CUTOFF, swiatlo1[6][0]);

  glLightf(GL_LIGHT1, GL_CONSTANT_ATTENUATION, swiatlo1[7][0]);
  glLightf(GL_LIGHT1, GL_LINEAR_ATTENUATION, swiatlo1[8][0]);

  glLightf(GL_LIGHT1, GL_QUADRATIC_ATTENUATION, swiatlo1[9][0]);
    }

  

else

 glDisable(GL_LIGHT1);

}

Funkcja rysująca stożek – reflektor

void

 Rysuj(

double

 r)

{

 

 swiatlo1[3][0]=PromienReflektora*(cos(alfa));
 swiatlo1[3][1]=nachyelenie;

 swiatlo1[3][2]=PromienReflektora*(sin(alfa));
 swiatlo1[4][0]=-(PromienReflektora*cos(alfa));

     swiatlo1[4][1]=-nachylenie;
     swiatlo1[4][2]=-(PromienReflektora*sin(alfa));

glPushMatrix(); 
glTranslatef(PromienReflektora*(cos(alfa)),nachylenie,PromienReflektora*(

sin(alfa)));

 glutSolidSphere(0.5,10,10);

 glPopMatrix();
 alfa+=PredkoscReflektora;

(…)
}

background image

3.3.2 Opis

Implementację pierwszego źródła światła rozpoczynamy od deklaracji macierzy z 

parametrami źródła światła i tak:

I ambient – świtało otoczenia ustawione na 0,0,0 aby zapewnić efekt realistycznego 

reflektora 

II diffuse – światło rozproszenia ustawione na 1,0,1 oznacza kolor fioletowy
III specular - światło lustrzane ustawione na 1,0,1 oznacza kolor fioletowy
IV possition – pozycja reflektora w deklaracji nie ma znaczenia gdyż jest zmienna
V direction – kierunek świecenia w deklaracji nie ma znaczenia gdyż jest zmienny
VI exponent – domyślnie brak tlumienia
VII spot_cutoff – kąt odcięcia 45 stopni
VIII constant attenuation – ustawiłem tutaj stałe natężenie na 0.9
IX linear attenuation – wartość domyślna
X linear attenuation – wartość domyślna

W funkcji WlaczOswietlenie() ładowane są parametry źródła światła za pomocą funkcji 

glLightfv(GL_LIGHT1, PARAMETR, swiatlo1[nr wiersza])

. Posłużyłem się tutaj również 

zmienną boolowską Zrodlo1, która ustawiamy na 1 gdy chcemy, aby światło było włączone 
lub na 0, gdy chcemy, aby było wyłączone.

W funkcji rysującej na początku ustawiane są parametry światła, które nie zostały ustawione 
w deklaracji czyli położenie i kierunek świecenia przeciwny do położenia. Za pomocą 
funkcji 

glutSolidSphere(0.5,10,10);

 zobrazowany jest reflektor poruszający się po orbicie 

zależnej od zmiennej 

nachylenie

 i 

PromienReflektora. 

Animacja reflektora polega na 

zmianie kąta

 alfa(

w radianach) w każdej klatce animacji o zmienną 

PredkoscReflektora

.

           

3.3.3

Efekt

background image

b) Zmiana promienia orbity oraz kąta nachylenia reflektora:

3.4 Źródło numer 2

3.4.1 Implementacja

Deklaracja macierzy:

GLfloat swiatlo2[10][4]= {
    {0.0, 1.0, 0.0, 0.0},  

// [0] otoczenie

    {0.0, 1.0, 0.0, 0.0},  

// [1] rozproszenie

    {0.0, 1.0, 0.0, 0.0},  

// [2] lustrzane

    {-10.0, -5.0, 10.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

    {180.0, 0.0, 0.0, 0.0},

// [6] kat odciecia swiatla

    {0.0, 0.0, 0.0, 0.0},  

// [7] stale tlumienie

    {0.7, 0.0, 0.0, 0.0},  

// [8] tlumienie liniowe

    {0.0, 0.0, 0.0, 0.0}}; 

// [9] tlumienie kwadratowe;

          

 Funkcje ładujące macierze z parametrami oświetlenia:

void

 WlaczOswietlenie(

void

)

{
  glEnable(GL_LIGHTING);

  

if

(Zrodlo2==1){

  glEnable(GL_LIGHT0);

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

  glLightfv(GL_LIGHT0, GL_DIFFUSE, swiatlo2[1]);
  glLightfv(GL_LIGHT0, GL_SPECULAR, swiatlo2[2]);

  glLightfv(GL_LIGHT0, GL_POSITION, swiatlo2[3]);  
  glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION, swiatlo2[4]);

  glLightf(GL_LIGHT0, GL_SPOT_EXPONENT, swiatlo2[5][0]);

background image

  glLightf(GL_LIGHT0, GL_SPOT_CUTOFF, swiatlo2[6][0]);

  glLightf(GL_LIGHT0, GL_CONSTANT_ATTENUATION, swiatlo2[7][0]);
  glLightf(GL_LIGHT0, GL_LINEAR_ATTENUATION, swiatlo2[8][0]);

  glLightf(GL_LIGHT0, GL_QUADRATIC_ATTENUATION, swiatlo2[9][0]);
    }

  

else

 glDisable(GL_LIGHT0);

 }

3.4.2 Opis

Implementację drugiego źródła światła rozpoczynamy od deklaracji macierzy z 
parametrami źródła światła i tak:
I ambient –światło otoczenia ustawione na 0,1,0 oznacza kolor zielony
II diffuse – światło rozproszenia ustawione na 0,1,0 oznacza kolor zielony
III specular - światło lustrzane ustawione na 0,1,0 oznacza kolor zielony
IV possition – pozycja ustawiona jest zgodnie z treścią zadania na (-5,-10,10)
V direction – kierunek świecenia na obiekt
VI exponent – domyślnie brak tlumienia
VII spot_cutoff – kąt odcięcia ma wartość 180 oznacza, że światło rozchodzi się 
równomiernie
VIII constant attenuation – wartość domyślna
IX linear attenuation – ustawiłem natężenie na 0,7
X linear attenuation – wartość domyślna

W funkcji WlaczOswietlenie() ładowane są parametry źródła światła za pomocą 
funkcji 

 glLightfv(GL_LIGHT1, PARAMETR, swiatlo1[nr wiersza])

. Posłużyłem się tutaj 

również zmienną boolowską Zrodlo2, która ustawiamy na 1 gdy chcemy, aby światło 
było włączone lub na 0, gdy chcemy, aby było wyłączone

3.4.3 Efekt

Źródło nr 2:

background image

Źródło nr 2 + Źródło nr 1:

4. Obsługa klawiatury.
4.1 Implementacja

void

 ObslugaKlawiatury(

unsigned

 

char

 klawisz)

{
  

if

(klawisz == 

'['

)      OBSERWATORODLEGLOSC -= 1;

  

else

 

if

 (klawisz == 

']'

)      OBSERWATORODLEGLOSC +=1;

  

else

 

if

 (klawisz == 

'-'

&& N >= 8)

  N-=2;

  

else

 

if

 (klawisz == 

'+'

&& N <= 128)

  N+=2; 

  

else

 

if

 (klawisz == 

'*'

 && N2>= 4) 

  N2 -=2;

  

else

 

if

 (klawisz == 

'9'

 && N2 <= 64)    N2 +=2; 

  

else

 

if

 (klawisz == 

'1'

)   Zrodlo1 = 1;

  

else

 

if

 (klawisz == 

'!'

)   Zrodlo1 = 0;

  

else

 

if

 (klawisz == 

'2'

)   Zrodlo2= 1;

  

else

 

if

 (klawisz == 

'@'

)   Zrodlo2 = 0;

  

else

 

if

 (klawisz == 

'd'

)   OBSERWATOROBROTY +=1.0;  

  

else

 

if

 (klawisz == 

'D'

)   OBSERWATOROBROTY -=1.0; 

  

else

 

if

 (klawisz == 

'r'

 && PromienReflektora> 3)

  ref_r -=1.0;

  

else

 

if

 (klawisz == 

'R'

 && PromienReflektora < 15)  ref_r +=1.0;

  

else

 

if

 (klawisz == 

'f'

 )  nachylenie-=1.0;

  

else

 

if

 (klawisz == 

'F'

 )  nachylenie+=1.0;

  

else

 

if

 (klawisz == 

'4'

)   PredkoscReflektora=0.001;

  

else

 

if

 (klawisz == 

'5'

)   PredkoscReflektora=0.02;

  

else

 

if

 (klawisz == 

'6'

)   PredkoscReflektora =0.1;

  

else

 

if

 (klawisz == 

'q'

)   r -=0.1;

  

else

 

if

 (klawisz == 

'Q'

)   r +=0.1;

  

else

 

if

 (klawisz == 

'w'

 && WYSOKOSC > 0.2)

WYSOKOSC -=0.1;

  

else

 

if

 (klawisz == 

'W'

)   WYSOKOSC +=0.1;

  

else

 

if

 (klawisz == 27)

      exit(0);      

}

background image

    4.2 Opis

Dzięki powyższej implementacju użytkownik ma możliwość wpływania na parametery 
znajdujące się w funkcji wyświetlającej jedną klatkę animacji. Ogólnie rzecz biorąc obsługa 
klawiatury polega na tym, że po wciśnięciu klawisza, który porównywany jest z wartością w 
warunku if następuje inkrementacja bądź dekrementacja (z odpowiednim krokiem wynikającym 
z treści zadania) wartości parametru, który odpowiada danemu klawiszowi. Następnie każda 
zmienna, która została zmodyfikowana w tej funkcji jest również widzialna w funkcji 
WyswietlObraz, gdyż jest to zmienna globalna. 

4.3

Efekty

a) Zmiana liczby podziałów

background image

b) Zmiana wielkości bryły – zwiększenie promienia i zmniejszenie wysokości

c)Zmiana odległości obserwatora

d)Obrót wokół osi Y

background image

 5. Wnioski końcowe.

Ćwiczenie to pozwoliło mi rozwinąć swoje umiejętności w kwestii modelowania 

oświetlenia. Nie było to zadanie łatwe, ponieważ musiałem poświęcić dużo czasu na 
zgłębienie wiedzy teoretycznej dotyczącej modelowania oświetlenia przy pomocy biblioteki 
OpenGL. Ponadto,jak się później okazało, sama wiedza teoretyczna nie wystarczy i potrzebne 
jest tutaj spore doświadczenie, gdyż często parametry oświetlenia i materiału trzeba dobierać 
metodą prób i błędów, a ocena realistyczności danego efektu jest dość subiektywna. W trakcie 
wykonywania zadania na laboratoriach z powodu problemów ze sprzętem(nieprawidłowe 
wyświetlanie) ciężko było zrealizować zadanie zgodnie z instrukcją, gdyż nie mogłem 
sprawdzić poprawności mojego rozwiązania. Dało mi to do myślenia, że pomimo 
„przenośności” biblioteki OpenGL nie wszystkie elementy działają tak samo na różnych 
maszynach np. szybkość animacji jest zależna od szybkości maszyny, a problemy z 
wyświetlaniem mogą być spowodowane nieaktualnymi sterownikami karty graficznej.


Document Outline