Www.mg.edu.rs



Matematička gimnazija

Kraljice Natalije 37

Beograd

Maturski rad iz informatike

SIMULACIJA ELASTIČNIH TELA

Mentor: Učenik:

Profesor Milan Čabarkapa Jovan Rnjak, 4e

Beograd, 28/5/2012

Sadržaj

Strana

Uvod...............................................................................2

1. OpenGL/GLUT..........................................................4

2. Struktura podataka

2.1 Klasa Point.....................................................6

2.2 Klasa Constraint.............................................7

2.3 Klasa Body.....................................................8

3. Tok Programa

3.1 Računanja sila...............................................10

3.2 Integracija......................................................13

3.3 Detekcija kolizije i reakcija.......................... 16

3.4 Inicjalizacija...................................................23

3.5 Prikaz.............................................................27

3.6 Update ciklus.................................................29

Zaključak........................................................................31

Uvod

Ovaj rad predstavlja moj prvi korak u svet grafičke simulacije, kao i moj prvi “ozbiljni” program i namera mi je da se nadograđujem u tom smeru ubuduće. Sam rad kombinira elemente najinteresantnijih predmeta sa kojim sam se susreo tokom školovanja u Matematičkoj gimnaziji. To su informatika, fizika, numerika i linearna algebra.

Pri izboru programskog jezika dvoumio sam se između C++ i Python-a. Moji prvi pokusaji su bili u Python-u, privukla me je jednostavnija sintaksa, kao i intuitivnije metode za manipulaciju podataka. Ispostavilo se da ta jednostavnost ima visoku cenu, pored sporije brzine nedostajao mi je temeljiti debugger i Python-ov “weak typing” je uzrokovalo veliku neorganizaciju sa moje strane, pa je moj konačni izbor bio C++. Nažalost jake tačke C-a su istovremeno moje loše tačke; mnogo vremena sam proveo pokušavajući da razrešim greške izazvane “ilegalnim” pokazivačima, korupcije stek-a i drugih anomalija koje cenim da sam sam nekako izazvao, indirektno.

Izbor grafičkog API-a (Application Programming Interface) je bio lakši. Direct3D je zavisan od Windows-a i da bi ga koristio trebao bi se služiti sa WinAPI-om, a s tim bi i sam metod crtanja bio suviše kompleksan, tako da sam se odlučio za OpenGL sa dodatkom GLUT toolkit-a. ()

Simulacija se bazira na ideji da su sva tela izgrađena od tačaka koje su međusobno spojene oprugama. Ovakva vrsta simulacije nije fizički precizna, ali sa dobrim konfiguracijama koeficijenata opruga, trenja i gravitacije, moguće je dobiti veoma prihvatljive reakcije od simuliranih tela. Simulacija se odvija u dve prostorne dimenzije.

Izrada programske logike kao i source kod je uglavnom moj samostalni rad (sa izuzetkom GLUT templejta sa kojim sam počeo) i samim tim je implementacija prilično neoptimalna na nekim mestima. Ipak mislim da ta jednostavnost implementacije lakše otkriva suštinu ovakvih programa i shodno tome čitanje ovog rada bi poslužilo kao dobar uvod u principe grafičkih simulacija.

1. OpenGL/GLUT

void main(int argc, char** argv)

{

//--------------------------------------------------------------------------

// OpenGL / GLUT init / Window init

//--------------------------------------------------------------------------

glutInit( &argc, argv ); //Inicijalizacija OpenGL-a/GLUT-a

glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH); //Tip buffer-a

glutInitWindowSize (width, height); //Atributi prozora

glutInitWindowPosition (0, 0);

glutCreateWindow ("Soft Body Dynamics");

glShadeModel(GL_SMOOTH); //Opcije za anti-aliasing

glEnable(GL_POINT_SMOOTH);

glEnable(GL_LINE_SMOOTH);

glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);

glEnable (GL_BLEND); //Opcije za blend

glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

glDisable (GL_DEPTH_TEST);

glDisable (GL_LIGHTING);

glutDisplayFunc (Display); //Funkcija za crtanje

glutReshapeFunc (Reshape); //Event-Handler za promenu dimenzije prozora

glutTimerFunc (0, Timer, (float) 180.0f / 60.0f); //Glavni update loop

glutPassiveMotionFunc (PassiveMotion);

glutMouseFunc (Mouse); //Event-Handleri za Mis/tastaturu

glutKeyboardFunc (Keyboard);

Init ();

glutMainLoop ();

}

void Reshape(int w, int h)

{

width = w;

height = h;

glViewport( 0, 0, w, h);

}

void Timer(int t)

{

Update();

Display();

glutTimerFunc(t, Timer, t);

}

void Motion(int x, int y)

{

mouse_x = x;

mouse_y = y;

}

void Mouse(int buttons, int state, int x, int y)

{

mouse_x = x;

mouse_y = y;

if (buttons == GLUT_LEFT_BUTTON)

{

if (state == GLUT_DOWN)

mouse_b |= 1;

else

mouse_b &= ~1;

}

if (buttons == GLUT_RIGHT_BUTTON)

{

if (state == GLUT_DOWN)

mouse_b |= 2;

else

mouse_b &= ~2;

}

}

void Keyboard(unsigned char k, int x, int y)

{

char c=toupper(k);

switch(c)

{

case 'G':gravity=!gravity;break;

case '4':scenario=3;glutReshapeWindow(800,600);glutPostRedisplay();Init();break;

case '3':scenario=2;glutReshapeWindow(800,800);glutPostRedisplay();Init();break;

case '2':scenario=1;glutReshapeWindow(800,600);glutPostRedisplay();Init();break;

case '1':scenario=0;glutReshapeWindow(1200,800);glutPostRedisplay();Init();break;

case 'W':wireframe=!wireframe;break;

case 'F':coutvx=0;

this->dx=0;

this->vy=0;

this->dy=0;

}

Point::Point(int x,int y,float InvMass)

{

this->x=x;

this->y=y;

this->InvMass=InvMass;

this->vx=0;

this->dx=0;

this->vy=0;

this->dy=0;

}

Klasa Point predstavlja jedinični element svih tela. Sastoji se od položaja tačke u prostoru, kao i njene brzine i ubrzanja. Uzeo sam inverznu masu radi lakšeg definisanja statičnih tela (ona tela čija masa teži ka beskonačnosti, dakle inverzna masa je nula). Baferi za brzinu i položaj su neophodni da bi se sprečila zavisnost izračunatih sila od redosleda po kojim se računa.

3.2 Klasa Constraint

class Constraint

{

public:

int A; //Prva,

int B; //i Druga tačka.

float Coefficient; //Koeficijent elastičnosti

float RelaxDistance; //Ravnotežno rastojanje

Constraint(){this->A=0;this->B=0;}; //Konstruktor

Constraint(int, int, float, float); //Konstruktor A,B,Koeficijent,Ravnotežno rastojanje

Constraint(int,int,float); //Konstruktor A,B,Koeficijent

};

Constraint::Constraint(int A, int B, float Coefficient)

{

this->A=A;

this->B=B;

this->Coefficient=Coefficient;

}

Constraint::Constraint(int A, int B, float Coefficient, float RelaxDistance)

{

this->A=A;

this->B=B;

this->Coefficient=Coefficient;

this->RelaxDistance=RelaxDistance;

}

Klasa Constraint predstavlja oprugu unutar jednog tela. A i B predstavljaju položaj tačke u nizu tačaka jednog tela.

Konstante i globalne varijable

float mouse_x = 0.0f; //Položaj miša na x-osi

float mouse_y = 0.0f; //Polozaj miša na y-osi

int mouse_b = 0; //Superpozicija pritisnutih dugmi na mišu (bit flag/field)

float dtu= 1.0f /60.0f; //Step za integraciju

float dtu6 = dtu/6.0;

float width =800; //Dužina prozora

float height = 600; //Visina prozora

bool wireframe=0; //Wireframe on/off

const int MAX_BODIES =20; //Maksimalan broj tela u jednom sistemu

int scenario=0; //Trenutni scenario

bool gravity=1;

3.3 Klasa Body

class Body

{

public:

Point* PointCloud; //Niz tačaka

Constraint* Constraints; //Niz opruga

int CollGroup;

int* CollPoints;

int NumCollPoints; //Ukupan broj CollPoints

int NumPoints; //Ukupan broj tačaka tela

int NumConstraints; //Ukupan broj opruga

int ThisI; //Indeks tela

bool CheckCollision[MAX_BODIES]; //Označava da li će telo proveravati preklope sa i-tim telom

bool* Outside; //Oznaćava za i-tu tačku da li se nalazi na spoljašnost.

Body(); //Konstruktor

Body(int,int,int); //Konstruktor NumPoints, NumConstraints, NumCollPoints

void AssignCollPoints(int[],int); //Učitavanje niza CollPoints

void AddPoint(Point, int); //Dodaj tačku

void AddConstraint(Constraint,int); //Dodaj oprugu i automatski zadaj RelaxDistance u zavisnosti od unesenih tacaka.

void AddConstraint2(Constraint,int); //Dodaj oprugu

void CalculateSprings(); //Izračunaj sile opruga

void CalculateAttraction(int sign); //Izracunaj odbojnu/privlačnu silu miša

void ApplyForces(); //v+=a

void ApplyWall(); //Zid prozora

void Gravity(); //Gravitacija

void FrictionWall(); //Trenje sa ivicom prozora

};

Klasa Body predstavlja telo definisano preko niza masa i opruga (Point i Constraint).

Metod koji sam koristio za određivanje preklpanja dva tela isključivo funkcioniše za konveksna tela, zato je bilo potrebno razdvojiti telo na više konveksni poligona i za svaki takav poligon posebno proveravati moguća preklapanja. CollGroup je broj stranica tih poligona. Optimalan broj stranica za većinu tela je četiri ( retki su slučajevi konkavnih četvorouglova ) i pritom imamo duplo manje poligona na kojima trebamo da proveravamo preklop, nego kad bismo delili tela na trouglove.

Važno je uočiti da ovakvom podelom ne moramo obavezno da celokupno prekrijemo prvobitno telo, to jest interesuje nas samo spoljašnji sloj jer su tu sudari najčešći.

CollPoints je jednodimenzionalan niz tih poligona. Važno je napomenuti da redosled kojim se upisuju tačke je bitan. Pre svega imamo da indeksi i, i+1, i+2, i+3 za i=4*k (CollGroup=4) moraju da obrazuju željeni poligon, a pri tom tačke moraju biti orijentisane u smeru kazaljke na satu. Ovo olakšava računanje normala nad parovima tih tačaka.

Primer dva različita ali pojednako validna niza za ilustrovano telo:

0 1 2 CollPoints={0,1,4,3,1,2,5,4,4,5,8,7,3,4,7,6}

3 4 5 CollPoints={2,5,4,1,3,4,7,6,3,0,1,4,4,5,8,7}

6 7 8

Body::Body(int NumPoints, int NumConstraints, int NumCollPoints)

{

PointCloud=new Point[NumPoints];

Constraints=new Constraint[NumConstraints];

CollPoints=new int[NumCollPoints];

this->NumConstraints=NumConstraints;

this->NumPoints=NumPoints;

this->NumCollPoints=NumCollPoints;

this->Outside=new bool[NumPoints];

for(int i=0;iConstraints[i].RelaxDistance

=Dist(PointCloud[A].x,PointCloud[A].y,PointCloud[B].x,PointCloud[B].y);

this->Constraints[i].Coefficient=C.Coefficient;

}

void Body::AddConstraint2(Constraint C, int i)

{

Constraints[i]=C;

}

void Body::AssignCollPoints(int Array[], int len)

{

for(int i=0;i0)PointCloud[i].vx=0;

}

else if(PointCloud[i].x0)PointCloud[i].vy=0;

}

else if(PointCloud[i].y ................
................

In order to avoid copyright disputes, this page is only a partial summary.

Google Online Preview   Download