Wojskowa Akademia Techniczna im. Jarosława Dąbrowskiego
Laboratorium Grafiki Komputerowej
Sprawozdanie do ćwiczenia laboratoryjnego nr 2
Wykonujący ćwiczenie: Maciej Laszuk grupa I7X1S1
Data wykonania :02.02.2009
1.Zadnie 1
Wykorzystując biblioteki OpenGL i GLUT napisać program wyświetlający perspektywiczny obraz obiektu przedstawionego na rysunku:
Obiekt należy zamodelować w trybach:
-GL_QUADS
-GL_TRIANGLES_FAN
Z uwzględnieniem możliwaości interakcyjnego wprowadzenia następujących parametrów:
- wysokości obiektu,
-średnicy obiektu,
-grubości ścian,
-liczby podziałów pionowych
Program powinien umożliwiać zmianę położenia obserwatora (odległość od obiektu i obroty wokół osi Y, X i Z)
2. Sposób rozwiązania zadania:
W celu rozwiązanie zadania należało użyć programu Microsoft Visual Studio oraz zmodyfikować program sześcian.c udostępniony przez prowadzącego ćwiczenia. Program można podzielić na dwie części. Część odpowiedzialną za narysowanie bryły na ekranie monitora oraz część zajmującą się przekształceniami bryły.
a.)Rysowanie bryły
void RysujSzescian(double a)
{
double x;
//podstawa dolna
glColor3f(0.1,0.9,0.1);
glBegin(GL_TRIANGLE_FAN);
glVertex3f(0.0,0.0,0.0);
for(x=0.0;x<=360.0;x+=360.0/podzialka2)
{
glVertex3f(r*cos(radian(x)) , 0 , r*sin(radian(x)));
}
glEnd();
//podstawa gorna
glBegin(GL_TRIANGLE_FAN);
glVertex3f(0.0,h*0.15,0.0);
for(x=0.0;x<=360.0;x+=360.0/podzialka2)
{
glVertex3f(r*cos(radian(x)) , h*0.15 , r*sin(radian(x)));
}
glEnd();
//zalamianie podstawy
glBegin(GL_QUADS);
glVertex3f( r , 0.0, 0.0);
for(x=0.0;x<=360.0;x+=360.0/podzialka1)
{
glVertex3f(r*cos(radian(x)) , 0 , r*sin(radian(x)));
glVertex3f(r*cos(radian(x+360.0/podzialka1)) , 0 ,r*sin(radian(x+360.0/podzialka1)));
glVertex3f((r+g)*cos(radian(x+360.0/podzialka1)) , h*0.15 ,(r+g)*sin(radian(x+360.0/podzialka1)));
glVertex3f((r+g)*cos(radian(x)) , h*0.15, (r+g)*sin(radian(x)));
}
glEnd();
//sciana boczna zewnetrzna
glBegin(GL_QUADS);
for(x=0.0;x<360.0;x=x+360.0/podzialka1)
{
glVertex3f((r+g)*cos(radian(x)) , h*0.15 , (r+g)*sin(radian(x)));
glVertex3f((r+g)*cos(radian(x+360.0/podzialka1)) , h*0.15 ,(r+g)*sin(radian(x+360.0/podzialka1)));
glVertex3f((r+g)*cos(radian(x+360.0/podzialka1)) , h ,(r+g)*sin(radian(x+360.0/podzialka1)));
glVertex3f((r+g)*cos(radian(x)) , h , (r+g)*sin(radian(x)));
}
glEnd();
//pierscien na gorze
glBegin(GL_QUADS);
for(x=0.0;x<360.0;x=x+360.0/podzialka1)
{
glVertex3f(r*cos(radian(x)) , h , r*sin(radian(x)));
glVertex3f(r*cos(radian(x+360.0/podzialka1)) , h ,r*sin(radian(x+360.0/podzialka1)));
glVertex3f((r+g)*cos(radian(x+360.0/podzialka1)) , h ,(r+g)*sin(radian(x+360.0/podzialka1)));
glVertex3f((r+g)*cos(radian(x)) , h , (r+g)*sin(radian(x)));
}
glEnd();
//sciana boczna wewnetrzna
glBegin(GL_QUADS);
for(x=0.0;x<360.0;x=x+360.0/podzialka1)
{
glVertex3f(r*cos(radian(x)) , h*0.15 , r*sin(radian(x)));
glVertex3f(r*cos(radian(x+360.0/podzialka1)) , h*0.15 ,r*sin(radian(x+360.0/podzialka1)));
glVertex3f(r*cos(radian(x+360.0/podzialka1)) , h ,r*sin(radian(x+360.0/podzialka1)));
glVertex3f(r*cos(radian(x)) , h , r*sin(radian(x)));
}
glEnd();
//ucho
glBegin(GL_QUADS);
glVertex3f(0,0.3*h,r+g);
glVertex3f(0.5,0.3*h,r+g);
glVertex3f(0.5,0.3*h,r+0.4*r+g);
glVertex3f(0,0.3*h,r+0.4*r+g);
glVertex3f(0.5,0.3*h,r+0.4*r+g);
glVertex3f(0,0.3*h,r+0.4*r+g);
glVertex3f(0,0.35*h,r+0.5*r+g);
glVertex3f(0.5,0.35*h,r+0.5*r+g);
glVertex3f(0,0.35*h,r+0.5*r+g);
glVertex3f(0.5,0.35*h,r+0.5*r+g);
glVertex3f(0.5,0.75*h,r+0.5*r+g);
glVertex3f(0,0.75*h,r+0.5*r+g);
glVertex3f(0,0.75*h,r+0.5*r+g);
glVertex3f(0.5,0.75*h,r+0.5*r+g);
glVertex3f(0.5,0.8*h,r+0.4*r+g);
glVertex3f(0,0.8*h,r+0.4*r+g);
glVertex3f(0.5,0.8*h,r+0.4*r+g);
glVertex3f(0,0.8*h,r+0.4*r+g);
glVertex3f(0,0.8*h,r+g);
glVertex3f(0.5,0.8*h,r+g);
/////////////////////
glVertex3f(0,0.3*h-0.3,r+g);
glVertex3f(0.5,0.3*h-0.3,r+g);
glVertex3f(0.5,0.3*h-0.3,r+0.4*r+g+0.3);
glVertex3f(0,0.3*h-0.3,r+0.4*r+g+0.3);
glVertex3f(0.5,0.3*h-0.3,r+0.4*r+g+0.3);
glVertex3f(0,0.3*h-0.3,r+0.4*r+g+0.3);
glVertex3f(0,0.35*h-0.3,r+0.5*r+g+0.3);
glVertex3f(0.5,0.35*h-0.3,r+0.5*r+g+0.3);
glVertex3f(0,0.35*h-0.3,r+0.5*r+g+0.3);
glVertex3f(0.5,0.35*h-0.3,r+0.5*r+g+0.3);
glVertex3f(0.5,0.75*h+0.3,r+0.5*r+g+0.3);
glVertex3f(0,0.75*h+0.3,r+0.5*r+g+0.3);
glVertex3f(0,0.75*h+0.3,r+0.5*r+g+0.3);
glVertex3f(0.5,0.75*h+0.3,r+0.5*r+g+0.3);
glVertex3f(0.5,0.8*h+0.3,r+0.4*r+g+0.3);
glVertex3f(0,0.8*h+0.3,r+0.4*r+g+0.3);
glVertex3f(0.5,0.8*h+0.3,r+0.4*r+g+0.3);
glVertex3f(0,0.8*h+0.3,r+0.4*r+g+0.3);
glVertex3f(0,0.8*h+0.3,r+g);
glVertex3f(0.5,0.8*h+0.3,r+g);
glEnd();
}
Analizując powyższy kod łatwo zauważyć, że bryła narysowana jest przy pomocy dwóch trybów: GL_TRIANGLE_FAN oraz GL_QUADS. Zastosowanie tych trybów narzuciły wymogi zadania. Różnica w ich zastosowaniu jest ogromna. Pierwsza i chyba najważniejszą jest typ rysowanego wielokąt. GL_TRIANGLE_FAN generuje trójkąt natomiast GL_QUADS kwadrat. Co za tym idzie również sposób deklarowanych wierzchołków musi być inny(choćby z uwagi na ich ilość). W pierwszym trybie każdy trójką ma jeden wierzchołek wspólny - p1. Natomiast trójką deklaruje się w następujący sposób (p1,p2,p3) (p1,p4,p5) (p1,p6,p7) itd. W drugim trybie generowane są nie połączone ze sobą kwadraty tak więc deklaracja wierzchołków odbywa się w następujący sposób: (p1,p2,p3,p4) (p5,p6,p7,p8) itd.
Ponieważ zadanie charakteryzowało się sporą dowolnością wyboru odnośnie konkretnego zastosowania trybu stwierdziłem, że najwygodniej będzie mi posłużenie się trybem GL_TRIANGLE_FAN do zamodelowania podstawy zewnętrznej i wewnętrznej natomiast trybu GL_QUADS użyłem przy modelowaniu reszty obiektu. Przy większości z części kubka musiałem posłużyć się pętlą , otrzymać pożądaną trygonometryczność obiektu jak również liczbę podziałów pionowych. Jest to w moim przekonaniu dość prosty i efektywny sposób modelowania bryły. Wyjątek stanowi ucho. Najłatwiej było uzyskać pożądany efekt deklarując punkt po punkcie kolejne kwadraty.
Uzyskany efekt (20 podziałów pionowych):
b.)Przekształcenia bryły
void WyswietlObraz(void)
{
// Wyczyszczenie bufora koloru i bufora glebokosci
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
// Przejscie w tryb modyfikacji macierzy przeksztalcen geometrycznych
glMatrixMode(GL_MODELVIEW);
// Zastapienie aktywnej macierzy macierza jednostkowa
glLoadIdentity();
// Ustalenie polozenia obserwatora
glTranslatef(0, 0, -OBSERWATOR_ODLEGLOSC);
glRotatef(xRot, 1, 0, 0);
glRotatef(yRot, 0, 1, 0);
glRotatef(zRot, 0, 0, 1);
// Narysowanie szescianu
RysujSzescian(bok);
// Przelaczenie buforow ramki
glutSwapBuffers();
}
//////////////////////////////////////////////////////////////////////////////////////////
// Funkcja obslugi klawiatury
void ObslugaKlawiatury(unsigned char klawisz, int x, int y)
{
switch(klawisz){
case '1' : podzialka1++;break;
case '!' : podzialka1--;break;
case '2' : h+=0.5;break;
case '@' : if(h>1) h-=0.5;break;
case '3' : g+=0.1;break;
case '#' : if(g>0.2)g-=0.1;break;
case '4' : r+=0.1;break;
case '$' : if(r>0.2)r-=0.1;break;
case '5' : OBSERWATOR_ODLEGLOSC ++;break;
case '%' : OBSERWATOR_ODLEGLOSC --;break;
case '6' : xRot ++;break;
case '^' : xRot--;break;
case '7' : yRot++;break;
case '&' : yRot--;break;
case '8' : zRot++;break;
case '*' : zRot--;break;
}
}
Po prawidłowym zamodelowaniu bryły należało umożliwić interaktywność obiektu.
Zadnie okazało się dość proste. Wystarczyło deklarowane punkty uzależnić od zmiennych odpowiedzialnych za wysokość obiektu, promień, grubość ścian oraz liczbę podziałów pionowych. Do obrotu wokół osi X, Y, Z użyłem funkcji glRotatef. Natomiast zmianę odległości od obiektu uzyskałem stosując funkcję glTranslatef. Obie funkcje znajdujące się w bibliotece GL/glut.h umożliwiają w niezwykle łatwy sposób uzyskanie pożądanego efektu. Aby użytkownik mógł dowolnie manipulować podanymi wcześniej przekształceniami dodałem w funkcji ObslugaKlawiatury klawisze za nie odpowiedzialne.
-zmiana ilości podziałów pionowych
Za zmianę odpowiedzialne są klawisze „1”,”!”
10 podziałów pionowych
40 podziały pionowy
Łatwo dostrzec różnice w szczegółowości , dokładności odwzorowania obiektu. Przy mniejszej liczbie podziałów kubek staje się dużo bardziej kanciasty przez co można powiedzieć, że przybiera kształt bryły foremnej a nie owalnej jak powinien. Zwiększając liczbę podziałów ściany zyskują owalność. Przy bardzo dużej liczbie podziałów chropowatość bryły jest praktycznie niewidoczna.
-Zmiana wielkości bryły
zmiana wysokości - klawisze `2' `@'
wysokość = 4
Wysokość =2
zmiana średnicy obiektu `4' `$'
średnica = 3
Średnica = 0.5
zmiana grubości ścian `3' `#'
grubość = 2
Grubość = 0.5
-Zmiana orientacji obserwatora
Obrót względem OX:
Względem OY:
Względem OZ:
3.) Deklaracja zmiennych.
Zamieszczam sposób zadeklarowanych przeze mnie zmiennych.
#include <GL/glut.h>
#include <math.h>
// Definicja stalych
#define DLUGOSC_BOKU 5.0
#define OBSERWATOR_FOV_Y 30.0
#define PI 3.1415926535897932384626433832795
// Zmienne globalne
double bok = DLUGOSC_BOKU; // Dlugosc boku szescianu
int szerokoscOkna = 800;
int wysokoscOkna = 600;
float OBSERWATOR_ODLEGLOSC = 20.0;
static GLfloat xRot = 0.0f;
static GLfloat yRot = 0.0f;
static GLfloat zRot = 0.0f;
float h = 4.0;
float r=1.0,podzialka1=20.0,podzialka2=12.0,g=0.5;
double radian(double a)
{
return (a*PI)/180;
}
double radian(double a)
{
return (a*PI)/180;
}
4.) Wnioski.
Celem laboratorium było sprawdzenie wiedzy z zakresu modelowania brył za pomocą trybów dostępnych w bibliotece GLU/GLUT przy modelowaniu brył oszukujących nasze oko. Kubek przez mnie stworzony składał się wyłącznie z kwadratów oraz trójkątów. Figur na pozór nie mających nic wspólnego z walcem pierścieniem czy stożkiem ściętym. Jednak dzięki zastosowaniu bardzo wielu podziałów pionowych bryła nabierała kształtów w dużej mierze przypominających kubek stosowany w życiu codziennym. Wynika z tego, że posługując się ledwie kilkoma figurami geometrycznymi jesteśmy w stanie zamodelować niemal każdą bryłę. Największym problemem podczas tego laboratorium było odpowiednie zadeklarowanie punktów stosując wzory trygonometryczne.