Kirjoittaja: dvd
Kirjoitettu: 19.12.2009 – 19.02.2012
Tagit: grafiikka, matematiikka, koodi näytille, vinkki
http://en.wikipedia.org/wiki/Sierpinski_triangle
Algoritmina käytän seuraavaa: Laske nykyisistä verteksistä 4 pienempää tetraedria (jotka muodostavat oikein aseteltuna alkup. tetraedrin) ja toista tämä jokaiselle uudelle tetraedrille. Kun on laskettu tarpeeksi uusia verteksejä, ne tallennetaan listaan.
Hieman tyhmästi tallennan jokaisen verteksin erikseen, tulee paljon piirtämistä. Optimointina voisi jokaisen verteksin tallentaa vain kerran ja sitten indeksoida niitä.
Koodi tarvitsee Windowsissa kirjastot SDL, opengl32 ja glu32.
Binääri: http://kuujoo.kapsi.fi/soodit/gfx/sierpinski3d/
#include <SDL/SDL.h> #include <SDL/SDL_opengl.h> #include <cmath> #include <vector> /* Simppeli verteksi luokka, tallentaa sijainnin ja RGB arvon(0-1) */ class SVertex { public: void setPos(float x_,float y_,float z_) { x=x_; y=y_; z=z_; } void setColor(float r_, float g_, float b_) { r=r_; g=g_; b=b_; } float x,y,z; float r,g,b; }; class CSierpinskiFractal { private: /* "Objektin" verteksit tallennetaan listaan, josta ne on helppo syöttää, esim. vertex arraylle. */ std::vector<SVertex>vlist; public: void clean() { vlist.clear(); } SVertex *getVertex(int id) { return &vlist.at(id); } int getVertexCount() { return vlist.size(); } void sierpinski3D(const SVertex &a, const SVertex &b, const SVertex &c, const SVertex &d, const int depth) { //mikäli ei olla piirto "syvyydessä" if(depth>0) { //luodaan 7 uutta verteksiä nykyisen "Tetrahedrin" sisälle, verteksit luodaan särmien puoleen väleihin SVertex np[6]; np[0].setPos((a.x+b.x)/2,(a.y+b.y)/2,(a.z+b.z)/2); np[0].setColor((a.r+b.r)/2,(a.g+b.g)/2,(a.b+b.b)/2); np[1].setPos((b.x+d.x)/2,(b.y+d.y)/2,(b.z+d.z)/2); np[1].setColor((b.r+d.r)/2,(b.g+d.g)/2,(b.b+d.b)/2); np[2].setPos((d.x+a.x)/2,(d.y+a.y)/2,(d.z+a.z)/2); np[2].setColor((a.r+d.r)/2,(a.g+d.g)/2,(a.b+d.b)/2); np[3].setPos((b.x+c.x)/2,(b.y+c.y)/2,(b.z+c.z)/2); np[3].setColor((b.r+c.r)/2,(b.g+c.g)/2,(b.b+c.b)/2); np[4].setPos((d.x+c.x)/2,(d.y+c.y)/2,(d.z+c.z)/2); np[4].setColor((d.r+c.r)/2,(d.g+c.g)/2,(d.b+c.b)/2); np[5].setPos((a.x+c.x)/2,(a.y+c.y)/2,(a.z+c.z)/2); np[5].setColor((a.r+c.r)/2,(a.g+c.g)/2,(a.b+c.b)/2); //kutsutaan rekursiivisesti uusilla arvoilla, sierpinski3D(a,np[0],np[5],np[2],depth-1); sierpinski3D(b,np[3],np[0],np[1],depth-1); sierpinski3D(c,np[5],np[3],np[4],depth-1); sierpinski3D(np[2],np[1],np[4],d,depth-1); } //mikäli ollaan piirtosyvyydessä... else { //asetetaan verteksit verteksilistaan. vlist.push_back(a); vlist.push_back(b); vlist.push_back(d); vlist.push_back(b); vlist.push_back(c); vlist.push_back(d); vlist.push_back(c); vlist.push_back(a); vlist.push_back(d); } } }; int main(int argc, char *argv[]) { SDL_Surface *screen = SDL_SetVideoMode(600, 600, 32, SDL_HWSURFACE | SDL_DOUBLEBUF|SDL_OPENGL); SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE,16); SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); glViewport(0, 0, 600, 600); glMatrixMode(GL_PROJECTION); gluPerspective(45, 600.0/600.0, 1, 100); glMatrixMode(GL_MODELVIEW); glEnable(GL_CULL_FACE); glEnable(GL_DEPTH_TEST); //alku vertexeillä määritetään koko systeemin koko SVertex vertices[4]; vertices[0].setColor(1,0,0); vertices[1].setColor(0,1,0); vertices[2].setColor(0,0,1); vertices[3].setColor(1,1,1); vertices[0].setPos(-5,-5,3); vertices[1].setPos(5,-5,3); vertices[2].setPos(0,-5,-5); vertices[3].setPos(0,5,0); CSierpinskiFractal frak; //syötetään lähtöarvot, ja "syvyys", fraktaalille. fraktaali laskee listaan verteksien paikat. frak.sierpinski3D(vertices[0],vertices[1],vertices[2],vertices[3],6); SDL_Event event; bool isRunning = true; while(isRunning) { SDL_PollEvent(&event); if ( event.type == SDL_QUIT ) { isRunning = false; } glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); glLoadIdentity(); glTranslatef(0,0,-20); //pyöritetään glRotatef(0.5*SDL_GetTicks()/10,0,1,0); glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_COLOR_ARRAY); //osoitin ensimmäisen verteksin x pisteeseen glVertexPointer(3, GL_FLOAT, sizeof(SVertex),&frak.getVertex(0)->x); //osoitin ensimmäisen verteksin punaiseen väriarvoon glColorPointer(3,GL_FLOAT, sizeof(SVertex),&frak.getVertex(0)->r); glDrawArrays(GL_TRIANGLES,0 , frak.getVertexCount()); glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_COLOR_ARRAY); SDL_GL_SwapBuffers(); } SDL_FreeSurface(screen); SDL_Quit(); return 0; }