sprawko-pieci, Studia, WAT Informatyka, s3 - GK - lab grafika komputerowa, Lab2


  1. Temat indywidualnego zadania laboratoryjnego

  1. Algorytm rozwiązania zadania - rysowanie zadanego obiektu

- kod programu

void InicjalizujWyrzutnie(void)

{

podstawa = gluNewQuadric();

gluQuadricDrawStyle(podstawa, GLU_LINE);

podstawaDyskGorny = gluNewQuadric();

gluQuadricDrawStyle(podstawaDyskGorny, GLU_LINE);

podstawaDyskDolny = gluNewQuadric();

gluQuadricDrawStyle(podstawaDyskDolny, GLU_LINE);

slup = gluNewQuadric();

gluQuadricDrawStyle(slup, GLU_LINE);

wyrzutniaPrawa = gluNewQuadric();

gluQuadricDrawStyle(wyrzutniaPrawa, GLU_LINE);

wyrzutniaPrawaDysk = gluNewQuadric();

gluQuadricDrawStyle(wyrzutniaPrawaDysk, GLU_LINE);

wyrzutniaLewaDysk = gluNewQuadric();

gluQuadricDrawStyle(wyrzutniaLewaDysk, GLU_LINE);

wyrzutniaLewa = gluNewQuadric();

gluQuadricDrawStyle(wyrzutniaLewa, GLU_LINE);

radar = gluNewQuadric();

gluQuadricDrawStyle(radar, GLU_LINE);

}

void RysujWyrzutnie(GLfloat obrotWyrzutniPion, GLfloat obrotWyrzutniPoz)

{

glColor3f(1.0,1.0,1.0);

glPushMatrix();

glPushMatrix();

glRotatef(-90.0, 1, 0, 0);

gluCylinder(podstawa, 3.0, 3.0, 1.0, 20, 4);

glTranslatef(0.0, 0.0, 1.0);

gluDisk(podstawaDyskGorny, 0.0, 3.0, 20, 4);

// - slup

gluCylinder(slup, 0.75, 0.75, 3.0, 20, 4);

glPopMatrix();

// belki w wyrzutniami

glPushMatrix();

glTranslatef(0.0, 1.0+3.0+0.5, 0.0);

glRotatef(obrotWyrzutniPoz, 0, 1, 0);

glRotatef(obrotWyrzutniPion, 1, 0, 0);

// - radar

gluSphere(radar, 0.75, 10, 10);

// - wyrzutnia prawa

glTranslatef(2.0, -1.0, -1.5);

gluDisk(wyrzutniaPrawaDysk, 0.0, 0.5, 20, 1);

gluCylinder(wyrzutniaPrawa, 0.5, 0.5, 4.0, 20, 4);

// - wyrzutnia lewa

glTranslatef(-4.0, 0.0, 0.0);

gluDisk(wyrzutniaLewaDysk, 0.0, 0.5, 20, 1);

gluCylinder(wyrzutniaPrawa, 0.5, 0.5, 4.0, 20, 4);

// - belka

glTranslatef(2.0, 0.5+0.125, 1.5);

glScalef(4.0, 0.25, 1.25);

glutWireCube(1);

glPopMatrix();

// Posprzatanie na stosie macierzy modelowania

glPopMatrix();

}

Narysowanie wyrzutni na ekranie jest wynikiem działania dwóch wyżej zamieszczonych funkcji. Pierwsza z nich jest odpowiedzialna na zainicjalizowanie wartości zmiennych wskaźnikowych zadeklarowanych globalnie. Są to wskaźniki do kwadryk:

GLUquadricObj *podstawa;

GLUquadricObj *podstawaDyskGorny;

GLUquadricObj *podstawaDyskDolny;

GLUquadricObj *slup;

GLUquadricObj *wyrzutniaPrawa;

GLUquadricObj *wyrzutniaPrawaDysk;

GLUquadricObj *wyrzutniaLewaDysk;

GLUquadricObj *wyrzutniaLewa;

GLUquadricObj *radar;

Każda z powyższych zmiennych jest inicjalizowana zgodnie z poniższym schematem:

- rezerwacja pamięci:

podstawa = gluNewQuadric();

- określenie typu kwadryki (u mnie linie GLU_LINE)

gluQuadricDrawStyle(podstawa, GLU_LINE);

Wynikiem działania funkcji są obiekty kwadryk liniowych przechowujących dane o rysowanych obiektach, na których bazuje rysując wyrzutnię rakiet.

Dalszym krokiem w kierunki realizacji zadania laboratoryjnego jest druga z zamieszczonych powyżej procedur. W oparciu o prymitywy przestrzenne i utworzone wcześniej kwadryki rysuje ona zadany obiekt.

W celu do poprawnego działania do procedury należy przekazać dwa parametry, które będą interpretowane zgodnie z poniższym schematem:

Na początku procedura przygotowuje macierz punktów dla obiektów, które nie ulegają rotacji. Są to podstawa oraz słup wyrzutni.

glPushMatrix();

glRotatef(-90.0, 1, 0, 0);

gluCylinder(podstawa, 3.0, 3.0, 1.0, 20, 4);

glTranslatef(0.0, 0.0, 1.0);

gluDisk(podstawaDyskGorny, 0.0, 3.0, 20, 4);

// - slup

gluCylinder(slup, 0.75, 0.75, 3.0, 20, 4);

glPopMatrix();

Dokonuje rotacji w celu zmiany kierunku rysowania walca stanowiącego postawę. Funkcją, którą wykorzystuje [gluCylinder(...)] rysuje wysokość walca w kierunku dodatniej osi Z. Zatem rotacja o 90° powoduje dla obserwatora zmianę osi Y z Z. W wyniku otrzymuje walec rysowany w pionie. Następnie następuje przesunięcie środka układu współrzędnych o wektor - glTranslatef(x, y, z), ponieważ walec rysowany jest od środka dolnej podstawy. Zatem zmuszony jestem o przemieszczenie się w pionie o wysokość podstawy w celu narysowania słupa. W wyniku działania tego fragmentu kodu otrzymuje:

0x01 graphic

Druga macierz zawiera punkty, które wg treści zadania, mają ulegać rotacjom.

glPushMatrix();

glTranslatef(0.0, 1.0+3.0+0.5, 0.0);

glRotatef(obrotWyrzutniPoz, 0, 1, 0);

glRotatef(obrotWyrzutniPion, 1, 0, 0);

// - radar

gluSphere(radar, 0.75, 10, 10);

// - wyrzutnia prawa

glTranslatef(2.0, -1.0, -1.5);

gluDisk(wyrzutniaPrawaDysk, 0.0, 0.5, 20, 1);

gluCylinder(wyrzutniaPrawa, 0.5, 0.5, 4.0, 20, 4);

// - wyrzutnia lewa

glTranslatef(-4.0, 0.0, 0.0);

gluDisk(wyrzutniaLewaDysk, 0.0, 0.5, 20, 1);

gluCylinder(wyrzutniaPrawa, 0.5, 0.5, 4.0, 20, 4);

// - belka

glTranslatef(2.0, 0.5+0.125, 1.5);

glScalef(4.0, 0.25, 1.25);

glutWireCube(1);

glPopMatrix();

Wstępnie dokonywana jest rotacja układu współrzędnych w pionie i poziomie zgodnie z wartościami zmiennych przekazywanych do procedury.

glRotatef(obrotWyrzutniPoz, 0, 1, 0);

glRotatef(obrotWyrzutniPion, 1, 0, 0);

W celu wykonania poprawnego obrotu środek układu współrzędnych (przed wykonaniem rotacji) zostaje przesunięty (translowany) do punktu [0.0; 4.5; 0.0] - jest to środek kuli wyrzutni.

glTranslatef(0.0, 1.0+3.0+0.5, 0.0);

Wg tego punktu dokonywane są rotacje.

Dalej przystępuje na rysowania wieżyczki wyrzutni począwszy od sfery:

gluSphere(radar, 0.75, 10, 10);

0x01 graphic

gdzie:

Kolejnym etapem jest rysowanie wyrzutni rakiet. Przesuwam się od środka sfery do punktu, gdzie będzie się znajdował środek podstawy walca imitującego wyrzutnie:

glTranslatef(2.0, -1.0, -1.5);

Następnie rysuje dysk, który będzie stanowił zamknięcie wyrzutni (podstawę walca):

gluDisk(wyrzutniaPrawaDysk, 0.0, 0.5, 20, 1);

i sam walec:

gluCylinder(wyrzutniaPrawa, 0.5, 0.5, 4.0, 20, 4);

Sąsiednia, 2 wyrzutnia jest rysowana zgodnie z powyższym schematem. Różnicą jest tylko wektor przesunięcia. Przemieszczam się nie od środka kuli, a środka dysku zamykającego wyrzutnie nr 1. Kod wygląda następująco:

glTranslatef(-4.0, 0.0, 0.0);

gluDisk(wyrzutniaLewaDysk, 0.0, 0.5, 20, 1);

gluCylinder(wyrzutniaPrawa, 0.5, 0.5, 4.0, 20, 4);

a efekt jego działania:

0x01 graphic

Ostatnim etapem rysowania wieżyczki jest belka łącząca wszystkie 3, wyżej rysowane, obiekty. Rysuję ją na końcu, ponieważ wykorzystuje w tym celu funkcję rysującą sześcian, której jako parametr podaje długość boku:

glutWireCube(1);

W celu otrzymania prostopadłościanu dokonuje przeskalowania osi przed narysowaniem sześcianu:

glScalef(4.0, 0.25, 1.25);

W wyniku czego każdy rysowany punkt sześcianu, a dokładniej jego współrzędne są przemnażane przed wartość przeskalowania (dla odpowiedniej osi). W ten sposób otrzymuje kompletną wieżyczkę, która wygląda następująco:

0x01 graphic

Natomiast kompletny, zamodelowany przeze mnie obiekt prezentuje się następująco:

0x01 graphic

  1. Algorytm rozwiązania zadania - zmiana położenia obserwatora

glTranslatef(0,0, -sqrt(odleglosc*odleglosc-wysokosc*wysokosc));

katX=(float)(asin(wysokosc/odleglosc)*180/PI);

glRotatef(katX, 1, 0, 0);

glRotatef(rotObsY,0,1,0);

Wyżej zamieszczony kod jest fragmentem funkcji odpowiedzialnej za wygenerowanie pojedynczej klatki animacji. Bezpośrednio po nim następuje wywołanie funkcji odpowiadającej za narysowanie wyrzutni (omówiona powyżej).

Działanie algorytmu opiera się o schemat:

Wstępnie następuje odsunięcie obserwatora od środka układu współrzędnych, gdzie rysowana jest wyrzutnia. Odsunięcie, po osi Z, wyznaczam z twierdzenia Pitagorasa i dokonuje translacji:

glTranslatef(0,0, -sqrt(odleglosc*odleglosc-wysokosc*wysokosc));

Następnie, zgodnie z powyższym schematem, wyznaczany jest kąt o jaki zostanie podniesiony obserwator - kąt rotacji względem osi X:

0x01 graphic

Ponieważ funkcje trygonometryczne wracają wartość w radianach, dlatego dokonuje zamiany wartości na stopnie:

0x01 graphic

O tak uzyskany kąt dokonuje rotacji względem osi X:

glRotatef(katX, 1, 0, 0);

A następnie wykonuje obrót obserwatora wokół obiektu - rotacje względem osi Y:

glRotatef(rotObsY,0,1,0);

Zmienna rotObsY przyjmuje wartości 0°-360° co umożliwia pełny obrót obserwatora wokół obiektu.

  1. Kod źródłowy programu

#include <GL/glut.h>

#include <math.h>

#define PI 3.141592653

// Wskazniki do wykorzystywanych kwadryk

GLUquadricObj *podstawa;

GLUquadricObj *podstawaDyskGorny;

GLUquadricObj *podstawaDyskDolny;

GLUquadricObj *slup;

GLUquadricObj *wyrzutniaPrawa;

GLUquadricObj *wyrzutniaPrawaDysk;

GLUquadricObj *wyrzutniaLewaDysk;

GLUquadricObj *wyrzutniaLewa;

GLUquadricObj *radar;

GLfloat rotObsY = 40.0;

GLfloat wysokosc = 15.0;

GLfloat odleglosc = 30.0;

GLfloat katX;

GLfloat rotPoz = 0.0;

GLfloat rotPion= 0.0;

void InicjujWyrzutnie(void)

{

podstawa = gluNewQuadric();

gluQuadricDrawStyle(podstawa, GLU_LINE);

podstawaDyskGorny = gluNewQuadric();

gluQuadricDrawStyle(podstawaDyskGorny, GLU_LINE);

podstawaDyskDolny = gluNewQuadric();

gluQuadricDrawStyle(podstawaDyskDolny, GLU_LINE);

slup = gluNewQuadric();

gluQuadricDrawStyle(slup, GLU_LINE);

wyrzutniaPrawa = gluNewQuadric();

gluQuadricDrawStyle(wyrzutniaPrawa, GLU_LINE);

wyrzutniaPrawaDysk = gluNewQuadric();

gluQuadricDrawStyle(wyrzutniaPrawaDysk, GLU_LINE);

wyrzutniaLewaDysk = gluNewQuadric();

gluQuadricDrawStyle(wyrzutniaLewaDysk, GLU_LINE);

wyrzutniaLewa = gluNewQuadric();

gluQuadricDrawStyle(wyrzutniaLewa, GLU_LINE);

radar = gluNewQuadric();

gluQuadricDrawStyle(radar, GLU_LINE);

}

void RysujWyrzutnie(GLfloat obrotWyrzutniPion, GLfloat obrotWyrzutniPoz)

{

glColor3f(0.0,0.0,0.0);

// Przygotowanie stosu macierzy modelowania

glPushMatrix();

// Rysowanie podstawy i slupa

glPushMatrix();

// - sciany boczne

glRotatef(-90.0, 1, 0, 0);

gluCylinder(podstawa, 3.0, 3.0, 1.0, 20, 4);

// - gorna podstawa

glTranslatef(0.0, 0.0, 1.0);

gluDisk(podstawaDyskGorny, 0.0, 3.0, 20, 4);

// - slup

gluCylinder(slup, 0.75, 0.75, 3.0, 20, 4);

glPopMatrix();

// belki w wyrzutniami

glPushMatrix();

glTranslatef(0.0, 1.0+3.0+0.5, 0.0);

glRotatef(obrotWyrzutniPoz, 0, 1, 0);

glRotatef(obrotWyrzutniPion, 1, 0, 0);

// - radar

gluSphere(radar, 0.75, 10, 10);

// - wyrzutnia prawa

glTranslatef(2.0, -1.0, -1.5);

gluDisk(wyrzutniaPrawaDysk, 0.0, 0.5, 20, 1);

gluCylinder(wyrzutniaPrawa, 0.5, 0.5, 4.0, 20, 4);

// - wyrzutnia lewa

glTranslatef(-4.0, 0.0, 0.0);

gluDisk(wyrzutniaLewaDysk, 0.0, 0.5, 20, 1);

gluCylinder(wyrzutniaPrawa, 0.5, 0.5, 4.0, 20, 4);

// - belka

glTranslatef(2.0, 0.5+0.125, 1.5);

glScalef(4.0, 0.25, 1.25);

glutWireCube(1);

glPopMatrix();

// Posprzatanie na stosie macierzy modelowania

glPopMatrix();

}

void WyswietlObraz(void)

{

glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);

glPushMatrix();

glTranslatef(0,0, -odleglosc);

katX=(float)(asin(wysokosc/odleglosc)*180/PI);

glRotatef(katX, 1, 0, 0);

glRotatef(rotObsY,0,1,0);

RysujWyrzutnie(rotPion, rotPoz);

glPopMatrix();

glutSwapBuffers();

}

void UstawParametryWidoku(int szerokosc, int wysokosc)

{

glViewport(0, 0, szerokosc, wysokosc);

glMatrixMode(GL_PROJECTION);

glLoadIdentity();

gluPerspective(40.0, (float)szerokosc/(float)wysokosc, 1.0, 1000.0);

glMatrixMode(GL_MODELVIEW);

glLoadIdentity();

}

void ObslugaKlawiszySpecjalnych(int klawisz, int x, int y)

{

switch(klawisz)

{

case GLUT_KEY_UP:

wysokosc = (wysokosc < odleglosc) ? wysokosc + 1.0 : wysokosc;

break;

case GLUT_KEY_DOWN:

wysokosc = (wysokosc > 0.0) ? wysokosc - 1.0 : wysokosc;

break;

case GLUT_KEY_LEFT:

rotObsY = (rotObsY > 0.0) ? rotObsY - 1.0 : 360.0;

break;

case GLUT_KEY_RIGHT:

rotObsY = (rotObsY < 360.0) ? rotObsY + 1.0 : 0.0;

break;

}

}

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

{

switch(klawisz)

{

case '1':

rotPion = (rotPion < 50.0) ? rotPion + 1.0 : rotPion; break;

case '!':

rotPion = (rotPion > -50.0) ? rotPion - 1.0 : rotPion; break;

case '2':

rotPoz = (rotPoz < 360.0) ? rotPoz + 1.0 : 0.0; break;

case '@':

rotPoz = (rotPoz > 0.0) ? rotPoz - 1.0 : 360.0; break;

case '3':

odleglosc = (odleglosc < 60.0) ? odleglosc + 1.0 : odleglosc; break;

case '#':

odleglosc = (wysokosc/odleglosc < 1) ? odleglosc - 1.0 : odleglosc; break;

}

if(klawisz == 27)

exit(0);

}

int main(int argc, char **argv)

{

glutInit(&argc, argv);

glutInitDisplayMode (GLUT_DOUBLE|GLUT_RGB|GLUT_DEPTH);

glutInitWindowPosition(100, 100);

glutInitWindowSize(400, 400);

glutCreateWindow("Wieza z klockow");

glEnable(GL_DEPTH_TEST);

glDepthFunc(GL_LEQUAL);

glClearDepth(1000.0);

glClearColor (1.0, 1.0, 1.0, 1.0);

glutDisplayFunc(WyswietlObraz);

glutReshapeFunc(UstawParametryWidoku);

glutIdleFunc(WyswietlObraz);

glutKeyboardFunc(ObslugaKlawiatury);

glutSpecialFunc(ObslugaKlawiszySpecjalnych);

InicjujWyrzutnie();

glutMainLoop();

return 0;

}

7

Copyright ©2005 Piotr Barankiewicz



Wyszukiwarka