Paszyński Lab3 Sprawozdanie

10

Click here to load reader

Transcript of Paszyński Lab3 Sprawozdanie

Page 1: Paszyński Lab3 Sprawozdanie

Janusz Paszyński 06.01.2008 I6Y1S1

Grafika Komputerowa Sprawozdanie z zajęć Laboratoryjnych

Oświetlenie

Page 2: Paszyński Lab3 Sprawozdanie

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

1. Typ obiektu: sfera o zmiennej parzystej liczbie podziałów pionowych i poziomych, 2. Właściwości materiału nr 1: fioletowy błyszczący (widziany w białym świetle), 3. Właściwości materiału nr 2: żółty 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 i poziomych. 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: biały, − natężenie: 1, − kąt odcięcia: 30o, − 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 kąta nachylenia orbity do osi OX, o kąta nachylenia orbity do osi OZ,

− kierunek świecenia: na obiekt.

Źródło nr 2: − typ: kierunkowe, − kolor: czerwony, − natężenie: 0.7, − położenie: stałe w punkcie P(10,10, 10) układu współrzędnych obserwatora. − kierunek świecenia: na obiekt.

Program powinien umożliwiać interaktywne, niezależne włączanie i wyłączanie źródeł światła. Należy również zapewnić użytkownikowi możliwość zmiany położenia obserwatora 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 [0o, 360o] z krokiem 1o.

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

2. Metoda Rozwiązania Pierwszym etapem jest wymodelowanie stożka. Przykładowy stożek może być opisany podstawowym równaniem matematycznym stożka, które dla lepszego efektu może być nieco przekształcone. Równanie takie może mieć postać:

Page 3: Paszyński Lab3 Sprawozdanie

222 Hyxz ++−=

⎥⎦⎤

⎢⎣⎡−∈

2;

2

,HHz

Ryx

Równanie to jest równaniem odwróconego stożka o rozwarciu 90o i podniesionego do góry o połowę swojej wysokości. Dzięki zastosowaniu tego przekształconego równania stożek jest umieszczony dokładnie na środku układu współrzędnych. Stożek najlepiej narysować używając współrzędnych walcowych. Do tego celu konieczne jest użycie dwóch zagnieżdżonych pętli do zmiany parametru ϕ, oraz parametru R, który jest równy współrzędnej z. Stożek ma się składać z dwóch materiałów o różnych właściwościach odbicia światła. Stożek jest więc podzielony na poziome pasy na przemian w kolorze czerwonym i żółtym. Dodatkowo pasy różnią się od siebie odbiciem światła. Przełączanie materiału jest realizowane poprzez zliczanie podziałów poziomych i dla podziału parzystego włączany jest materiał pierwszy, zaś dla podziału nieparzystego włączany jest materiał drugi. Definicje materiałów znajdują się w funkcjach:

void mat1(); void mat2();

Sprawdzenie parzystości podziału jest realizowane poprzez dzielenie modulo 2 licznika. Następnym etapem tworzenia sceny jest dodanie oświetlenia. Na początek należy ustawić parametry oświetlenia. Lampa pierwsza to światło kierunkowe. W programie korzystamy z faktu, że domyślnie światło w OpenGL jest tworzone jako światło kierunkowe. Parametry światła są umieszczone w tablicach o elementach typu GLfloat. Typ GLfloat na komputerach PC jest z reguły zgodny z typem float w języku C/C++, jednak aby uniknąć niejednoznaczności i niejawnego rzutowania tablice są deklarowane jako tablice typu GLfloat. Światło kierunkowe:

GLfloat amb[]={0.926,0.0,0.961,0.8}; GLfloat pos[]={10.0,10.0,10.0};

Pierwsza tablica przechowuje informacje o kolorze i natężeniu światła. Tablica druga zawiera informacje na temat położenia światła w przestrzeni trójwymiarowej. Reflektor:

GLfloat amb2[]={1.0,1.0,1.0,1.0}; GLfloat spo[3]; GLfloat pos2[3]; GLfloat odc=25.0;

Jak widać parametry pos2[3] i spo[3] nie zostały zainicjowane żadnymi wartościami. Pola tych tabel odpowiadających kolejno za położenie reflektora i kierunek jego świecenia muszą

Page 4: Paszyński Lab3 Sprawozdanie

być wyliczane dynamicznie, ponieważ jego położenie może być zmieniane przez użytkownika. Wyliczenie współrzędnych reflektora i kierunku jego świecenia jest zrealizowane poprzez zastosowanie współrzędnych sferycznych. Wyliczenie położenia reflektora:

pos2[0]=RR*cos(tt)*cos(pp); pos2[1]=RR*sin(pp); pos2[2]=RR*sin(tt)*cos(pp);

RR – odległość reflektora od środka układu współrzędnych tt – odchylenie od osi OX promienia wodzącego reflektora pp – odchylenie od osi OZ promienia wodzącego reflektor Wyliczenie wektora określającego kierunek świecenia reflektora jest wykonane przy wykorzystaniu wyliczonego położenia. Współrzędne wektora to kolejno współrzędne położenia reflektora pomnożone przez liczbę -1 w celu skierowania do środka układu, oraz podzielone przez długość promienia wodzącego reflektora RR w celu znormalizowania.

spo[0]=-pos2[0]/RR; spo[1]=-pos2[1]/RR; spo[2]=-pos2[2]/RR;

Ostatnim etapem tworzenia sceny jest wyliczenie wektorów normalnych do powierzchni. Z punktu widzenia implementacji etap ten jest wykonywany równolegle z modelowaniem stożka, jednak jest on na tyle istotny dla oświetlenia, że został pozostawiony na koniec. Aby wyliczyć wektor normalny do powierzchni konieczne jest wybranie dwóch wektorów leżących na danej powierzchni. Najłatwiej wybrać jest wektory od jakiegoś wierzchołka do dwóch sąsiednich. Dodatkowo wybrane wektory nie mogą być równoległe. Jeśli wybrane wektory będą równoległe wyliczony wektor będzie miał długość 0 i nie będzie mógł być użyty jako wektor normalny, ponieważ nie będzie możliwa jego normalizacja. Współrzędne wybranych wektorów zostały zamieszczone w dwóch tablicach trzyelementowych. W celu uzyskania wektora ortogonalnego do dwóch wektorów, trzeba te wektory pomnożyć wektorowo. Cały proces wyliczania wektora normalnego dla jednej płaszczyzny jest zamieszczony poniżej:

t[0]=nh*cos(ph)-h*cos(ph); t[1]=nh-h; t[2]=nh*sin(ph)-h*sin(ph); s[0]=nh*(cos(nph)-cos(ph)); s[1]=0; s[2]=nh*(sin(nph)-sin(ph)); n[0]=t[1]*s[2]-t[2]*s[1]; n[1]=t[2]*s[0]-t[0]*s[2];

Page 5: Paszyński Lab3 Sprawozdanie

Wyliczenie wektorów normalnych jest konieczne, aby uzyskać efekt oświetlenia możliwie najbardziej zbliżony do oświetlenia naturalnego. Algorytmy oświetlenia zaimplementowane w OpenGL bazują na wektorach normalnych, przez co oświetlenie nie działa jeśli powyższe nie zostaną ustawione jak należy.

n[2]=t[0]*s[1]-t[1]*s[0]; ln=sqrt(n[0]*n[0]+n[1]*n[1]+n[2]*n[2]); n[0]/=ln; n[1]/=ln; n[2]/=ln;

3. Wyniki programu

Przy małej liczbie podziałów pionowych efekt światła nie jest najlepszy. W ten sposób wygląda stożek dla ośmiu podziałów i włączonych obu źródeł światła.

Page 6: Paszyński Lab3 Sprawozdanie

Po wyłączeniu światła pierwszego dobrze widać działanie reflektora. Niestety dla tak małej liczby podziałów pionowych efekt nie jest zbyt zachęcający.

Po wyłączeniu obu źródeł światła scena nie jest w pełni ciemna. Możliwe jest rozpoznanie kolorów.

Page 7: Paszyński Lab3 Sprawozdanie

Dla dużej liczby podziałów poziomych bardzo dokładnie świeci reflektor. Q powyższym przykładzie ‘spot’ jest zamieszczony z prawej i lekko z góry obiektu.

4. Kod programu Funkcja rysująca stożek:

void stozek(float H,unsigned int pol,unsigned int row) { pol*=2; row*=2; if((pol==0)||(row==0)) return; GLfloat amb[]={0.926,0.0,0.961,0.8}; GLfloat amb2[]={1.0,1.0,1.0,1.0}; GLfloat pos[]={10.0,10.0,10.0}; GLfloat spo[3]; GLfloat pos2[3]; GLfloat odc=25.0; //liczymy kierunek spota spo[0]=-pos2[0]/RR; spo[1]=-pos2[1]/RR; spo[2]=-pos2[2]/RR;

Page 8: Paszyński Lab3 Sprawozdanie

glVertex3f(H*cos(ph),H,H*sin(ph));

glLightfv(GL_LIGHT0,GL_AMBIENT,amb); glLightfv(GL_LIGHT0,GL_POSITION,pos); glLightfv(GL_LIGHT1,GL_AMBIENT,amb2); glLightfv(GL_LIGHT1,GL_POSITION,pos2); glLightfv(GL_LIGHT1,GL_SPOT_CUTOFF,&odc); glLightfv(GL_LIGHT1,GL_SPOT_DIRECTION,spo); glEnable(GL_LIGHTING); if(!l1) glDisable(GL_LIGHT0); else glEnable(GL_LIGHT0); if(!l2) glDisable(GL_LIGHT1); else glEnable(GL_LIGHT1); glEnable(GL_COLOR_MATERIAL); glDepthFunc(GL_LEQUAL); //rysujemy sciane boczna double h=0,nh=0; double nph; double ph,eps,eps2; eps=2*PI/(pol/2); eps2=H/(2*row); ph=0; glTranslatef(0.0,H/2,0.0); glRotatef(180,1,0,0); double n[3],t[3],s[3],ln; int pas=0; for(h=0;h<H-(H/row)+eps2;h+=H/row) { if(pas%2) mat1(); else mat2(); pas++; for(ph=0;ph<(2*PI-2*PI/pol)+eps;ph+=2*PI/pol) { nph=ph+2*PI/pol; nh=h+H/row; glBegin(GL_QUADS); //count normals t[0]=nh*cos(ph)-h*cos(ph); t[1]=nh-h; t[2]=nh*sin(ph)-h*sin(ph); s[0]=nh*(cos(nph)-cos(ph)); s[1]=0; s[2]=nh*(sin(nph)-sin(ph)); n[0]=t[1]*s[2]-t[2]*s[1]; n[1]=t[2]*s[0]-t[0]*s[2]; n[2]=t[0]*s[1]-t[1]*s[0]; ln=sqrt(n[0]*n[0]+n[1]*n[1]+n[2]*n[2]); n[0]/=ln; n[1]/=ln; n[2]/=ln; //count normals end glNormal3f(n[0],n[1],n[2]); glVertex3f(h*cos(ph),h,h*sin(ph)); glVertex3f(nh*cos(ph),nh,nh*sin(ph)); glVertex3f(nh*cos(nph),nh,nh*sin(nph)); glVertex3f(h*cos(nph),h,h*sin(nph)); glEnd(); } } //rysujemy podstawy glBegin(GL_TRIANGLE_FAN);

Page 9: Paszyński Lab3 Sprawozdanie

double phi; for(ph=0;ph<(2*PI-2*PI/pol)+eps;ph+=2*PI/pol) { glVertex3f(H*cos(ph),H,H*sin(ph)); } phi=0; glVertex3f(H*cos(phi),H,H*sin(phi)); glVertex3f(0.0,H,0.0); glEnd(); glTranslatef(-1*pos2[0],-1*pos2[1],pos2[2]); glutSolidSphere(0.2,5,5); }

Funkcje ustawiające parametry materiałów:

void mat1() { GLfloat mat_shi[]={100.0}; glColor3f(1.0,1.0,0.0); glMaterialfv(GL_FRONT,GL_SHININESS,mat_shi); } void mat2() { GLfloat mat_shi[]={0.0}; glColor3f(1.0,0.0,0.0); glMaterialfv(GL_FRONT,GL_SHININESS,mat_shi); }

Obsługa klawiatury:

void ObslugaKlawiatury(unsigned char klawisz, int x, int y) { if (klawisz == 27) exit(0); if (klawisz == 's') kat+=0.1; if (klawisz == 'S') kat-=0.1; if (klawisz == 'P') p++; if (klawisz == 'p') { p--; if(p<=1) p=2; } if (klawisz == 'O') dod++; if (klawisz == 'o') { dod--; if(dod<=0) dod=1; } if (klawisz=='H') { H+=2*PI/360; if(H>PI/2) H=PI/2; }

Page 10: Paszyński Lab3 Sprawozdanie

if (klawisz=='h') { H-=2*PI/360; if(H<-PI/2) H=-PI/2; } if (klawisz=='q') pr-=0.1; if (klawisz=='e') pr+=0.1; if (klawisz=='R') Odl++; if (klawisz=='r') { Odl--; if (Odl<0.0) Odl=0.0; } if (klawisz=='1') l1=l1^1; //przerzutnik 2stanowy if (klawisz=='2') l2=l2^1; //przerzutnik 2stanowy if (klawisz=='+') RR+=1; if (klawisz=='-') { RR-=1; if(RR<=0.0) RR=0.5; } if (klawisz=='7') tt-=2*PI/60; if (klawisz=='8') tt+=2*PI/60; if (klawisz=='9') pp-=2*PI/60; if (klawisz=='0') pp+=2*PI/60; }

5. Wnioski Do poprawnego działania oświetlenia w scenie konieczne jest nie tylko odpowiednie ustawienie świateł i jego parametrów, ale także odpowiednio wyliczone wektory normalne. Przy takim wyliczeniu wektorów normalnych jak to wykorzystane przez mnie w tym programie nie jest możliwe zastosowanie realistycznych efektów oświetlenia, chyba że w modelu wprowadzi się więcej podziałów. Oświetlenie w OpenGL bazuje na wektorach normalnych. Niepoprawne wyliczenie ich powoduje powstanie przekłamań w obrazie, oraz bardzo nieciekawy obraz oświetlenia.