WOJSKOWA AKADEMIA TECHNICZNA
Sprawozdanie laboratoryjne z przedmiotu
GRAFIKA KOMPUTEROWA
Wykonujący ćwiczenie: Paweł Madejski
Prowadzący: dr inż. Marek Salamon
Data wykonania: 15.12.2008r
Grupa szkoleniowa: I7X1S1
MODELOWANIE OŚWIETLENIA
Zadanie 4.
Wykorzystując biblioteki OpenGL i GLUT napisać program przedstawiający perspektywiczny obraz obiektu o następujacych parametrach:
Typ obiektu: walec o zmiennej parzystej liczbie podziałów pionowych i poziomych,
Właściwości materiału nr 1: zielony matowy (widziany w białym świetle),
Właściwości materiału nr 2: fioletowy błyszczący (widziany w białym świetle),
Sposób przyporządkowania materiałów do obiektu zgodnie ze wzorem: pasy poziome z uwzględnieniem podziałów poziomych.
Obiekt należy oświetlić dwoma źródłami światła o następujących parametrach:
Źródło nr1:
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:
promienia orbity,
prędkości kątowej (3 różne prędkości),
kąta nachylenia orbity do osi OX
kierynek świecenia: na obiekt.
Ź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ż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 [0o, 360o] z krokiem 1o.
Oświetlony obiekt powinien zawsze znajdować się w centralnej części okna
Realizacja zadania laboratoryjnego
Funkcje ustawiające właściwości materiałów.
GLfloat material_fioletowy[4][4]=
{
{1,0,1,1},
{1,0,1,1},
{1,1,1,1},
{0,0,0,0}
};
GLfloat material_zielony[4][4]=
{
{0,1,0,1},
{0,0.5,0,1},
{0,1,0,1},
{128,0,0,0}
};
void Material_fioletowy()
{
glMaterialfv(GL_FRONT, GL_AMBIENT, material_fioletowy[0]);
glMaterialfv(GL_FRONT, GL_DIFFUSE, material_fioletowy[1]);
glMaterialfv(GL_FRONT, GL_SPECULAR, material_fioletowy[2]);
glMaterialf(GL_FRONT, GL_SHININESS, material_fioletowy[3][0]);
}
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]);
glMaterialf(GL_FRONT, GL_SHININESS, material_zielony[3][0]);
}
Obie te funkcje wykorzystuja zadeklarowane wczesniej tablice dwuwymiarowe jako argumenty wykorzystywane we wnetrzu. Kolejne wartosci ustawiane przez funkcje glMaterialfv() mają nastepujace znaczenia:
GL_FRONT - opisywana jest frontowa płaszczyzna prymitywów (można również użyć GL_BACK - tylna płaszczyzna oraz GL_FRONT_AND_BACK - obie płaszczyzny)
GL_AMBIENT - światło otaczające, nie pochodzi z żadnego kierunku, choć ma źródło. Wszystkie obiekty na scenie są nim równomiernie oświetlone ze wszystkich stron i na wszystkich powierzchniach.
GL_DIFFUSE - światło rozproszone. W przeciwieństwie do poprzedniej składowej ma zdefiniowane źródło. Jasność powierzchni zależy od kąta, pod jakim pada na nią światło. Światło rozproszone padające jest traktowane jako kierunkowe, w przypadku światła odbitego już jako bezkierunkowe.
GL_SPECULAR - światło odbłysków, ma kierunek i jest odbijane od powierzchni w jedną stronę.
GL_SHININESS - współczynnik tłumienia. Opisuje ile energii powino być odbite od powierzchni zazwyczaj ściśle powiązany z GL_SPECULAR (właściwości emisyjne mozna opisać za pomocą GL_EMISSION) .
Tablice opisu materialu określaja jego parametru za pomocą wektora RGBA (reed green blue alfa) z czego każda składowa mieści sie w przedziale <0;1>. Wyjatkiem w tym przypadku jest atrybut GL_SHININESS, który ma jeden parametr z przedziału <0; 27>.
Funkcje ustawiające właściwości światła.
GLfloat swiatlo_reflektor[5][4]=
{
{1,1,1,1},
{1,1,1,1},
{1,1,1,1},
{0,0,0,1},
{-1,0,0}
};
GLfloat swiatlo_glowne[5][4]=
{
{1,1,0,0.7},
{1,1,0,0.7},
{1,1,0,0.7},
{-10,10,10},
{0,0,0}
};
void Swiatlo_reflektor(){
glPushMatrix();
glEnable(GL_LIGHTING);
glRotatef(kat,0,1,0);
glRotatef(kat_z,0,0,1);
glTranslatef(R_L1,0,0);
glPushMatrix();
float vektor[1][4] = {{0.5,0,0.1,0}};
glTranslatef(0,3,0);
glMaterialfv(GL_FRONT, GL_AMBIENT, vektor[0]);
glutSolidSphere(0.5,10,10);
glPopMatrix();
glLightfv(GL_LIGHT0, GL_DIFFUSE, swiatlo_reflektor[1]);
glLightfv(GL_LIGHT0, GL_SPECULAR, swiatlo_reflektor[2]);
glLightfv(GL_LIGHT0, GL_POSITION, swiatlo_reflektor[3]);
glLightf (GL_LIGHT0, GL_SPOT_CUTOFF, 30.0);
glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION,swiatlo_reflektor[4]);
glLightf (GL_LIGHT0, GL_SPOT_EXPONENT, 1);
glPopMatrix();
}
void Swiatlo_glowne(){
glLightfv(GL_LIGHT1, GL_DIFFUSE, swiatlo_glowne[1]);
glLightfv(GL_LIGHT1, GL_SPECULAR, swiatlo_glowne[2]);
glLightfv(GL_LIGHT1, GL_POSITION, swiatlo_glowne[3]);
glLightfv(GL_LIGHT1, GL_SPOT_DIRECTION,swiatlo_glowne[4]);
}
Przedstawione funkcje określają i uruchamiają dwa rodzaje światła: kierunkowe włączane przez Swiatlo_glowne(); reflektora włączane przez funkcje Swiatlo_reflektor(). Bazują one podobnie jak funkcje opisujące materiał na macierzach o składowych wektorów RGBA. Obydwie funkcje są wywołane po narysowaniu obiektu (w funkcji RysujWalec();). Bardziej złożona w tym przypadku jest funkcja Swiatlo_reflektor() i to jest jeden z powodów dlaczego omówię przykład modelowania światła właśnie na jej podstawie. Drugim aspektem jest to iż funkcja Swiatlo_glowne() nie wnosi praktycznie żadnych nowych teoretycznych wiadomości do jej poprzedniczki.
Procedura zaczyna i kończy się od odłożenia na stosie macierzy i kończy się jej zdjęciem. Takie postępowanie jest uzasadnione tym iż w jej wnętrzu jest rysowana sfera która służy jako graficzne zobrazowanie miejsca źródła światła. Źródło to jest obracane wokół osi OY na podstawie zmiennej kąt (jest ona albo automatycznie inkrementowana/dekrementowana w funkcji WyswietlObraz(); bądź zmieniana o ustalony skok z klawiatury), nachylane do osi OZ pod kątem określonym przez zmienną kat_z (ustalaną przez operatora z klawiatury) oraz jest oddalane lub przybliżane do obiektu na podstawie zmiennej R_L1 ustalanej z klawiatury. Następnie jest rysowana zapowiedziana przeze mnie wcześniej sfera wraz z paroma „kosmetycznymi” detalami. Właściwa część zaczyna się dopiero w tym miejscu. Funkcja glLightfv(); ustawia parametry światła posługując się parametrami:
GL_LIGHTi - określa numer źródła światła charakteryzowany w danej chwili gdzie i należy do przedziału <0;7>).
GL_DIFUSE - jak w przypadku materiału.
GL_SPECULAR - działanie zbliżone do wykorzystanego w opisie materiału.
GL_POSITION - pozycja źródła w układzie współrzędnych.
GL_SPOT_CUTOFF - kąt odcięcia czyli kąt, w którym źródło oświetla przedmiot.
GL_SPOT_DIRECTION - wektor kierunku padania światła ze źródła.
GL_SPOT_EXPONENT - kątowe tłumienie światła. Domyślnie przyjmuje wartość 0 (brak tłumienia), maksymalnie może to być 27. Im większa wartość tym bardziej skupiona jest wiązka.
Światło jest włączane za pomocą funkcji glEnable(); natomiast wyłączane za pomocą glDisable();. Parametrami tych funkcji są numery źródeł świateł natomiast aby światło działało po wywołaniu takiej konstrukcji należy uprzednio odblokować oświetlenie za pomocą glEnable(GL_LIGHTING); Włączać jak i wyłączać oświetlenie możemy obsługiwać zadeklarowanymi wcześniej klawiszami.
Funkcja rysująca obiekt (walec w paski poziome o naprzemiennie zmiennych materiałach).
void RysujWalec(double h, double r, int nv, int nh)
{
double dH, dAlfa;
int i, j;
// Wyznaczenie kata wyznaczajacego pojedynczy wycinek pionowy
dAlfa = 360.0L/(double)nh;
// Wyznaczenie wysokosci pojedynczego wycinka poziomego
dH = h/(double)nv;
glPushMatrix();
glRotatef(180,0,1,0);
// Wyznaczanie wierzcholkow i wektorow normalnych powierzchni bocznych
for (i = 0; floor((i+1)*dH*1.0E10) <= floor(h*1.0E10); i++)
{
glBegin(GL_TRIANGLE_STRIP);
glNormal3f(0.0, 0.0, 1.0);
glVertex3f(0.0, (i + 1)*dH, r);
glVertex3f(0.0, i*dH, r);
if (i%2 == 0) Material_fioletowy();
else Material_zielony();
for (j = 1; j*dAlfa <= 360.0L + dAlfa; j++){
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++)
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++)
glVertex3f(r*sin(DEG2RAD(i*dAlfa)), h, r*cos(DEG2RAD(i*dAlfa)));
glEnd();
glPopMatrix();
Swiatlo_reflektor();
Swiatlo_glowne();
}
Ponieważ rysowanie za pomocą prymitywów było już omawiane przy okazji drugiego zadania laboratoryjnego nie będę omawiał sposobu utworzenia walca z możliwością interaktywnej zmiany podziałów pionowych i poziomych oraz promienia i wysokośći. Jedyną ciekawostką jest wykorzystanie w pierwszej pętli (odpowiadającej za konstrukcję pionowych podziałów) wyrażenia warunkowego od którego zależy wywołanie materiału według jakiego dany pasek będzie narysowany. if (i%2 == 0) Material_fioletowy();
else Material_zielony();
W tej funkcji kluczową rolę odgrywa konstrukcja glNormal3f(); wyznaczająca wektor normalny do powierzchni w naszym przypadku trójkąta opisującego połówkę szachownicy. Dla uściślenia wektor normalny jest to wektor prostopadły do powierzchni dla jakiej jest wyznaczany. Pomaga on określać położenie, orientację w przestrzeni dzięki czemu można określić kąty odbicia i padania światła.
Po wyznaczeniu wektorów dla każdej składowej walca należy wywołać funkcje oświetlenia.
Kolejne funkcje (poza RysujNakladke();) nie wnoszą nic nowego do tematu od poprzednich zajęć bądź są tylko dodatkiem do zadania o charakterze informującym (znów mamy do czynienia z RysujNakladke();). Nie będę ich więc omawiał. Ich prototypy oraz konstrukcje można zobaczyć w załączonym dalej kodzie źródłowym całego programu.
Wynik pracy.
Rys1. Ogólny widok zawartości okna programu zaraz po uruchomieniu bądź zresetowaniu ustawień (wartości domyślne).
Rys2. Walec z oświetleniem kierunkowym. Rys3. Walec z oświetleniem z reflektora.
Rys4. Walec ze zwiększoną liczbą podziałów poziomych i pionowych oświetlony obydwoma rodzajami światła.
Opis obsługi klawiatury:
'h' / 'H': zwiekszenie/zmniejszenie liczby podziałów poziomych siatki,
'v' / 'V': zwiekszenie/zmniejszenie liczby podziałów pionowych siatki,
'w' / 'W': zwiekszenie/zmniejszenie wysokośći walca,
'p' / 'P': zwiekszenie/zmniejszenie promienia walca,
'r': przywracanie wartości początkowych (domyślnych),
'q' / 'Q': włączanie/wyłączanie lampki (światło typu reflektor),
'a' / 'A': włączanie/wyłączanie światła kierunkowego,
'z' / 'Z': zwiększanie/zmniejszanie odległości lampki od obiektu,
'x' / 'X': zwiększanie/zmniejszanie prędkości kątowej obrotu lampki wokół osi OY,
'c' / 'C': zwiększanie/zmniejszanie kąta nachylenia lampki z osią OZ,
'+' / '-': zwiększanie/zmniejszanie odległości obiektu od obserwatora,
'.' / ',' : obrót walca w lewo/prawo wokół osi OY,
'←' / '→': przesunięcie lampki w lewo/prawo,
'↑' / '↓': zwiększanie/zmniejszanie kąta nachylenia lampki z osią OZ,
Wnioski:
Podczas ćwiczenia zadaniem było zamodelowanie figury o zadanym w treści stylu, materiale i oświetleniu. Celem było zaprzyjaźnienie się z bardzo ważną według mnie rolą światła oraz oświetlenia w programowaniu obiektów graficznych. Umiejętne posługiwanie się oświetleniem pozwala ożywić i stworzyć scenę bliższą rzeczywistemu odpowiednikowi danego obiektu. Wykorzystanie wielu świateł pozwala wzmocnić to złudzenie gdyż. Weźmy na przykład człowieka idącego po ulicy w słoneczne popołudnie, jego otoczenie i jego cień. Widać że potrzebne są co najmniej dwa rodzaje świateł do zamodelowania podobnego przykładu. Jedno ze źródeł jest to światło kierunkowe oświetlające całą scenę (słońce) natomiast drugie to człowiek który oświetla jakiś teren podłoża po którym się przemieszcza światłem typu reflektor (odpowiednik lampki zaimplementowanej w naszym przykładzie). Jeśli elementy sceny będą miały dobrze dobrane materiały oraz zostanie dobrze zaimplementowane światło wtedy wszystko razem będzie ładnie wyglądało.
Zadanie jakie mieliśmy wykonać podczas laboratorium było według mnie nastawione na przyswojenie podstawowej wiedzy o oświetleniu i materiałach. Miało ono też służyć jako przykład mieszania się różnych materiałów z różnym światłem.
Sądzę, iż zadanie wykonane zostało poprawnie i zgodnie z założeniami postawionymi w treści.
Kod źródłowy programu:
#include <math.h>
#include <string.h>
#include <stdio.h>
#include <GL/glut.h>
// Definicja stalych
#define LPOZ_MAX 100
#define LPOZ_MIN 4
#define LPION_MAX 100
#define LPION_MIN 4
#define R_MAX 10.0
#define WYS_MAX 5.0
#define KROK_FLOAT 0.1
#define X_OFFSET_SWIATLO 10
#define Y_OFFSET_SWIATLO 120
#define X_OFFSET_MAT 10
#define Y_OFFSET_MAT 220
#define X_OFFSET_OBIEKT 10
#define Y_OFFSET_OBIEKT 300
#define ID_MENU_SWIATLA 0
#define ID_MENU_MATERIALU 1
#define LPOZ_MENU_SWIATLA 10
#define LPOZ_MENU_MATERIALU 5
#define M_PI 3.14159
// Makro przeliczajace stopnie na radiany
#define DEG2RAD(x) ((float)(x)*M_PI/180.0)
// Zmienne globalne
double kat = 0.0; // Kat obrotu obserwatora wokol osi OY [stopnie]
int lPionowych; // Liczba podzialow pionowych
int lPoziomych; // Liczba podzialow poziomych
double promien; // Promien walca
double wysokosc; // Wysokosc walca
int sIndeks; // Wybrana pozycja w tablicy parametrow swiatla
int mIndeks; // Wybrana pozycja w tablicy parametrow materialu
int menu; // Identyfikator wybranego menu (menu swiatla lub menu materialu)
int szerokoscOkna = 800;
int wysokoscOkna = 600;
int poziom = 30;
int pion = 30;
float kat_x = 0, kat_z = 0, R_L1 = 10;
GLfloat OBSERWATOR_ODLEGLOSC=4;
GLfloat OBSERWATOR_OBROT_Y=0;
int lampka=0;
int gswiatlo=0;
// Tablica parametrow swiatla
GLfloat swiatlo_reflektor[5][4]=
{
{1,1,1,1},
{1,1,1,1},
{1,1,1,1},
{0,0,0,1},
{-1,0,0}
};
GLfloat swiatlo_glowne[5][4]=
{
{1,1,0,0.7},
{1,1,0,0.7},
{1,1,0,0.7},
{-10,10,10},
{0,0,0}
};
// Tablica parametrow materialu z jakiego wykonany jest walec
GLfloat material_fioletowy[4][4]=
{
{1,0,1,1},
{1,0,1,1},
{1,1,1,1},
{0,0,0,0}
};
GLfloat material_zielony[4][4]=
{
{0,1,0,1},
{0,0.5,0,1},
{0,1,0,1},
{128,0,0,0}
};
// Prototypy funkcji
void UstawDomyslneWartosciParametrow(void);
void RysujTekstRastrowy(void *font, char *tekst);
void RysujWalec(double h, double r, int nv, int nh);
void UstawParametryWidoku(int szer, int wys);
void RysujNakladke(void);
void WyswietlObraz(void);
void ObslugaKlawiatury(unsigned char klawisz, int x, int y);
void ObslugaKlawiszySpecjalnych(int klawisz, int x, int y);
void Material_fioletowy();
void Material_zielony();
void Swiatlo_reflektor();
void Swiatlo_glowne();
//////////////////////////////////////////////////////////////////////////////////////////
// Funkcja ustawiajaca domyslne parametry walca, materialu i zrodla swiatla
void UstawDomyslneWartosciParametrow(void)
{
lPionowych = 8; // Liczba podzialow pionowych
lPoziomych = 4; // Liczba podzialow poziomych
promien = 4.0; // Promien walca
wysokosc = 6.0; // Wysokosc walca
glDisable(GL_LIGHT0); // wylaczenie swiatla z lampki
glDisable(GL_LIGHT1); // wylaczenie swiatla otoczenia
kat_x = 0; // predkosc katowa lamki wzgledem osi OY
kat_z = 0; // kat nachylenia lampki do osi OX
kat = 0; // polozenie lampki wzgledem osi OY
R_L1 = 10; // promien orbity
OBSERWATOR_ODLEGLOSC=4; // odleglosc obserwatora od walca
OBSERWATOR_OBROT_Y=0; // kat obrotu wokol oso OY
lampka=0; // ustawienie wypisywaniastanu lampki na ekran
gswiatlo=0; // ustawienie wypisywania stanu swiatla glownego na ekran
glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);
}
//////////////////////////////////////////////////////////////////////////////////////////
// Funkcja rysujaca tekst rastrowy <tekst> za pomca fontow bitmapowych <font>.Rysowanie
// tekstu wykonywane jest poczawszy od biezacej pozycji ekranu.
void RysujTekstRastrowy(void *font, char *tekst)
{
int i;
for (i = 0; i < (int)strlen(tekst); i++)
glutBitmapCharacter(font, tekst[i]);
}
//////////////////////////////////////////////////////////////////////////////////////////
// Zdefiniowanie walasciwosci materialu walca na podstawie zapisanych w tablcy 'material'
// parametrow (material obowiazuje tylko do scian skierowanych przodem do obserwatora)
void Material_fioletowy()
{
glMaterialfv(GL_FRONT, GL_AMBIENT, material_fioletowy[0]);
glMaterialfv(GL_FRONT, GL_DIFFUSE, material_fioletowy[1]);
glMaterialfv(GL_FRONT, GL_SPECULAR, material_fioletowy[2]);
glMaterialf(GL_FRONT, GL_SHININESS, material_fioletowy[3][0]);
}
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]);
glMaterialf(GL_FRONT, GL_SHININESS, material_zielony[3][0]);
}
void Swiatlo_reflektor(){
glPushMatrix();
glEnable(GL_LIGHTING);
glRotatef(kat,0,1,0);
glRotatef(kat_z,0,0,1);
glTranslatef(R_L1,0,0);
glPushMatrix();
float vektor[1][4] = {{0.5,0,0.1,0}};
glTranslatef(0,3,0);
glMaterialfv(GL_FRONT, GL_AMBIENT, vektor[0]);
glutSolidSphere(0.5,10,10);
glPopMatrix();
glLightfv(GL_LIGHT0, GL_DIFFUSE, swiatlo_reflektor[1]);
glLightfv(GL_LIGHT0, GL_SPECULAR, swiatlo_reflektor[2]);
glLightfv(GL_LIGHT0, GL_POSITION, swiatlo_reflektor[3]);
glLightf (GL_LIGHT0, GL_SPOT_CUTOFF, 30.0);
glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION,swiatlo_reflektor[4]);
glLightf (GL_LIGHT0, GL_SPOT_EXPONENT, 1);
glPopMatrix();
}
void Swiatlo_glowne(){
glLightfv(GL_LIGHT1, GL_DIFFUSE, swiatlo_glowne[1]);
glLightfv(GL_LIGHT1, GL_SPECULAR, swiatlo_glowne[2]);
glLightfv(GL_LIGHT1, GL_POSITION, swiatlo_glowne[3]);
glLightfv(GL_LIGHT1, GL_SPOT_DIRECTION,swiatlo_glowne[4]);
}
//////////////////////////////////////////////////////////////////////////////////////////
// Funkcja rysujaca walec o zadanej wysokosci, promieniu oraz liczbie podzialow
// pionowych i poziomych. Tryb modelowania powierzchni bocznej - GL_TRIANGLE_STRIP,
// podstaw - GL_TRIANGLE_FAN.
void RysujWalec(double h, double r, int nv, int nh)
{
double dH, dAlfa;
int i, j;
// Wyznaczenie kata wyznaczajacego pojedynczy wycinek pionowy
dAlfa = 360.0L/(double)nh;
// Wyznaczenie wysokosci pojedynczego wycinka poziomego
dH = h/(double)nv;
glPushMatrix();
glRotatef(180,0,1,0);
// Wyznaczanie wierzcholkow i wektorow normalnych powierzchni bocznych
for (i = 0; floor((i+1)*dH*1.0E10) <= floor(h*1.0E10); i++)
{
glBegin(GL_TRIANGLE_STRIP);
glNormal3f(0.0, 0.0, 1.0);
glVertex3f(0.0, (i + 1)*dH, r);
glVertex3f(0.0, i*dH, r);
if (i%2 == 0) Material_fioletowy();
else Material_zielony();
for (j = 1; j*dAlfa <= 360.0L + dAlfa; j++){
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++)
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++)
glVertex3f(r*sin(DEG2RAD(i*dAlfa)), h, r*cos(DEG2RAD(i*dAlfa)));
glEnd();
glPopMatrix();
Swiatlo_reflektor();
Swiatlo_glowne();
}
//////////////////////////////////////////////////////////////////////////////////////////
// Funkcja ustawiajaca parametry rzutu perspektywicznego i rozmiary viewportu
void UstawParametryWidoku(int szer, int wys)
{
// Zapamietanie wielkosci widoku
szerokoscOkna = szer;
wysokoscOkna = wys;
// Ustawienie parametrow viewportu
glViewport(0, 0, szerokoscOkna, wysokoscOkna);
// Przejscie w tryb modyfikacji macierzy rzutowania
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(40.0, (float)szerokoscOkna/(float)wysokoscOkna, 1.0, 1000.0);
// Przejscie w tryb modyfikacji macierzy przeksztalcen geometrycznych
glMatrixMode(GL_MODELVIEW);
// Zmiana macierzy znajdujacej sie na wierzcholku stosu na macierz jednostkowa
glLoadIdentity();
}
//////////////////////////////////////////////////////////////////////////////////////////
// Funkcja rysujaca na wygenerowanym obrazie walca nkladke z tekstem opisujacym
// aktualne parametry zrodla swiatla i materialu.
void RysujNakladke(void)
{
char buf[255];
// Zmiana typu rzutu z perspektywicznego na ortogonalny
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
glOrtho(0.0, szerokoscOkna, 0.0, wysokoscOkna,-100.0, 100.0);
// Modelowanie sceny 2D (zawartosci nakladki)
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
// Zablokowanie oswietlenia (mialoby ono wplyw na kolor tekstu)
glDisable(GL_LIGHTING);
// Okreslenie koloru tekstu
glColor3f(1.0, 1.0, 1.0);
// RYSOWANIE MENU PARAMETROW ZRODLA SWIATLA reflektora
sprintf(buf, "Lampka");
glRasterPos2i(X_OFFSET_SWIATLO, Y_OFFSET_SWIATLO);
RysujTekstRastrowy(GLUT_BITMAP_8_BY_13, buf);
sprintf(buf, " - katowa predkosc (%.1f) x,X", kat_x);
glRasterPos2i(X_OFFSET_SWIATLO, Y_OFFSET_SWIATLO - 10);
RysujTekstRastrowy(GLUT_BITMAP_8_BY_13, buf);
sprintf(buf, " - promien orbity (%.1f) z,Z", R_L1);
glRasterPos2i(X_OFFSET_SWIATLO, Y_OFFSET_SWIATLO - 20);
RysujTekstRastrowy(GLUT_BITMAP_8_BY_13, buf);
sprintf(buf, " - kat nachylenia do osOX (%.1f) up,down", kat_z);
glRasterPos2i(X_OFFSET_SWIATLO, Y_OFFSET_SWIATLO - 30);
RysujTekstRastrowy(GLUT_BITMAP_8_BY_13, buf);
sprintf(buf, " - wlaczona lampka (%s)", (lampka == 1)? "tak":"nie");
glRasterPos2i(X_OFFSET_SWIATLO, Y_OFFSET_SWIATLO - 40);
RysujTekstRastrowy(GLUT_BITMAP_8_BY_13, buf);
// RYSOWANIE MENU PARAMETROW polozenia
glColor3f(1.0, 1.0, 1.0);
sprintf(buf, "polozenie");
glRasterPos2i(X_OFFSET_MAT, Y_OFFSET_MAT);
RysujTekstRastrowy(GLUT_BITMAP_8_BY_13, buf);
sprintf(buf, " - swiatlo (%s)", (gswiatlo == 1)? "tak": "nie");
glRasterPos2i(X_OFFSET_MAT, Y_OFFSET_MAT - 10);
RysujTekstRastrowy(GLUT_BITMAP_8_BY_13, buf);
sprintf(buf, " - odleglosc od obserwatora (%.1f)", OBSERWATOR_ODLEGLOSC);
glRasterPos2i(X_OFFSET_MAT, Y_OFFSET_MAT - 20);
RysujTekstRastrowy(GLUT_BITMAP_8_BY_13, buf);
sprintf(buf, " - obrot wokol OY (%.1f)", OBSERWATOR_OBROT_Y);
glRasterPos2i(X_OFFSET_MAT, Y_OFFSET_MAT - 30);
RysujTekstRastrowy(GLUT_BITMAP_8_BY_13, buf);
// RYSOWANIE MENU PARAMETROW WALCA
glColor3f(1.0, 1.0, 1.0);
sprintf(buf, "Walec:");
glRasterPos2i(X_OFFSET_OBIEKT, Y_OFFSET_OBIEKT);
RysujTekstRastrowy(GLUT_BITMAP_8_BY_13, buf);
sprintf(buf, " - promien (%.1f)", promien);
glRasterPos2i(X_OFFSET_OBIEKT, Y_OFFSET_OBIEKT - 10);
RysujTekstRastrowy(GLUT_BITMAP_8_BY_13, buf);
sprintf(buf, " - wysokosc (%.1f)", wysokosc);
glRasterPos2i(X_OFFSET_OBIEKT, Y_OFFSET_OBIEKT - 20);
RysujTekstRastrowy(GLUT_BITMAP_8_BY_13, buf);
sprintf(buf, " - podzialow pionowych (%d)", lPionowych);
glRasterPos2i(X_OFFSET_OBIEKT, Y_OFFSET_OBIEKT - 30);
RysujTekstRastrowy(GLUT_BITMAP_8_BY_13, buf);
sprintf(buf, " - podzialow poziomych (%d)", lPoziomych);
glRasterPos2i(X_OFFSET_OBIEKT, Y_OFFSET_OBIEKT - 40);
RysujTekstRastrowy(GLUT_BITMAP_8_BY_13, buf);
// Przywrocenie macierzy sprzed wywolania funkcji
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
// Odblokowanie oswietlenia
glEnable(GL_LIGHTING);
}
//////////////////////////////////////////////////////////////////////////////////////////
// Funkcja generujaca pojedyncza klatke animacji
void WyswietlObraz(void)
{
// Wyczyszczenie bufora ramki i bufora glebokosci
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
// Okreslenie wielkosci widoku, wlaczenie rzutowania perspektywicznego
// i zainicjowanie stosu macierzy modelowania
UstawParametryWidoku(szerokoscOkna, wysokoscOkna);
// Ustawienie oswietlenia sceny (polozenie zrodla swiatla wyznaczane jest w ukladzie
// wspolrzednych obserwatora)
//WlaczOswietlenie();
// Wyznaczenie polozenia obserwatora (przeksztalcenie uladu wspolrzednych
// sceny do ukladu wspolrzednych obserwatora). Obserwator obraca sie wokol punktu 0.0
// na osi OY. Promien obrotu = 20, pochylenie = 20 stopni,
// predkosc obrotu = 0.25 stopnia/ramke.
glTranslatef(0, -5-wysokosc/6+2, -20);
glTranslatef(0, 0 , -OBSERWATOR_ODLEGLOSC);
glRotatef(OBSERWATOR_OBROT_Y, 0, 1, 0);
// Generacja obrazu walca
RysujWalec(wysokosc, promien, lPoziomych, lPionowych);
// Narysowanie tekstow z opisem parametrow oswietlenia i materialu
RysujNakladke();
// Przelaczenie buforow ramki
glutSwapBuffers();
// Modyfikacja kata obrotu
kat += kat_x;
}
//////////////////////////////////////////////////////////////////////////////////////////
// Funkcja obslugi klawiatury
void ObslugaKlawiatury(unsigned char klawisz, int x, int y)
{
switch(klawisz)
{
case 'v':
lPionowych = (lPionowych == LPION_MAX)? LPION_MAX : lPionowych + 2;
break;
case 'V':
lPionowych = (lPionowych == LPION_MIN)? LPION_MIN : lPionowych - 2;
break;
case 'h':
lPoziomych = (lPoziomych == LPOZ_MAX)? LPOZ_MAX : lPoziomych + 2;
break;
case 'H':
lPoziomych = (lPoziomych == LPOZ_MIN)? LPOZ_MIN : lPoziomych - 2;
break;
case 'w':
wysokosc = (wysokosc == WYS_MAX) ? WYS_MAX : wysokosc + 1;
break;
case 'W':
wysokosc = (wysokosc == 1) ? wysokosc : wysokosc - 1;
break;
case 'p':
promien = (promien == R_MAX) ? R_MAX : promien + 1;
break;
case 'P':
promien = (promien == 1) ? promien : promien - 1;
break;
case 'r':
UstawDomyslneWartosciParametrow();
break;
case 'q' : glEnable(GL_LIGHT0);
lampka = 1;
break;
case 'Q' : glDisable(GL_LIGHT0);
lampka = 0;
break;
case 'a' : glEnable(GL_LIGHT1);
gswiatlo = 1;
break;
case 'A' : glDisable(GL_LIGHT1);
gswiatlo = 0;
break;
case 'z' : R_L1 += 0.1;break;
case 'Z' : R_L1 -= 0.1;break;
case 'x' : kat_x = (kat_x == 3) ? 3 : kat_x+1;
break;
case 'X' : kat_x = (kat_x == -3) ? 3 : kat_x-1;
break;
case 'c' : kat_z++;break;
case 'C' : kat_z--;break;
case '+' : OBSERWATOR_ODLEGLOSC++;break;
case '-' : OBSERWATOR_ODLEGLOSC--;break;
case '.' : OBSERWATOR_OBROT_Y = (OBSERWATOR_OBROT_Y == 360) ? 0 : OBSERWATOR_OBROT_Y + 1;break;
case ',' : OBSERWATOR_OBROT_Y = (OBSERWATOR_OBROT_Y == 0) ? 360 : OBSERWATOR_OBROT_Y - 1;break;
// Wcisniecie klawisza ESC powoduje wyjscie z programu
case 27:
exit(0);
}
}
//////////////////////////////////////////////////////////////////////////////////////////
// Funkcja klawiszy specjalnych
void ObslugaKlawiszySpecjalnych(int klawisz, int x, int y)
{
switch(klawisz)
{
case GLUT_KEY_UP:
kat_z++;break;
case GLUT_KEY_DOWN:
kat_z--;break;
case GLUT_KEY_LEFT:
kat++;break;
case GLUT_KEY_RIGHT:
kat--;break;
}
}
//////////////////////////////////////////////////////////////////////////////////////////
// Glowna funkcja programu
int main(int argc, char **argv)
{
// Zainicjowanie biblioteki GLUT
glutInit(&argc, argv);
// Ustawienie trybu wyswietlania
glutInitDisplayMode (GLUT_DOUBLE|GLUT_RGBA|GLUT_DEPTH);
// Ustawienie polozenia dolenego lewego rogu okna
glutInitWindowPosition(100, 100);
// Ustawienie rozmiarow okna
glutInitWindowSize(szerokoscOkna, wysokoscOkna);
// Utworzenie okna
glutCreateWindow("i7x1s1 Madejski ***Lab 4");
// Odblokowanie bufora glebokosci
glEnable(GL_DEPTH_TEST);
// Ustawienie funkcji wykonywanej na danych w buforze glebokosci
glDepthFunc(GL_LEQUAL);
// Ustawienie wartosci czyszczacej zawartosc bufora glebokosci
glClearDepth(1000.0);
// Odblokowanie wykonywania operacji na skladowych "alfa"
glEnable(GL_BLEND);
// Wybor funkcji mieszajacej kolory
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
// Ustawienie koloru czyszczenia bufora ramki
glClearColor (0.3, 0.3, 0.0, 0.0);
// Zarejestrowanie funkcji (callback) wyswietlajacej
glutDisplayFunc(WyswietlObraz);
// Zarejestrowanie funkcji (callback) wywolywanej za kazdym razem kiedy
// zmieniane sa rozmiary okna
glutReshapeFunc(UstawParametryWidoku);
// Zarejestrowanie funkcji wykonywanej gdy okno nie obsluguje
// zadnych zadan
glutIdleFunc(WyswietlObraz);
// Zarejestrowanie funkcji obslugi klawiatury
glutKeyboardFunc(ObslugaKlawiatury);
// Zarejestrowanie funkcji obslugi klawiszy specjalnych
glutSpecialFunc(ObslugaKlawiszySpecjalnych);
// Ustawienie domyslnych wartosci parametrow
UstawDomyslneWartosciParametrow();
// Obsluga glownej petli programu (wywolywanie zarejestrowanych callbackow
// w odpowiedzi na odbierane zdarzenia lub obsluga stanu bezczynnosci)
glutMainLoop();
return 0;
}