Sierpinski镂垫是一个非常有趣的图案, 有着悠久的历史, 在分形几何中等领域里引起了人们极大地兴趣, 是用递归和随机方式定义的几何形状, 在极限情况下, 它所表现的性质并没有随机性.
生成算法如下:
(1)在三角形内部随机选取一个点作为初始点
(2)在三角形的3个顶点中随机选取一个,求出该顶点与初始点连线的中点,画出该中点
(3)将(2)中的中点作为初始点,转到(2)
下面利用SDL+OpenGL分别在二维和三维中来实现。
二维
/***************************************************************************** Copyright: 2012, ustc All rights reserved. contact:[email protected] File name: main.c Description:Sierpinski 2d. Author:Silang Quan Version: 1.0 Date: 2012.12.02 *****************************************************************************/ #include <SDL/SDL.h> #include <GL/gl.h> #include <GL/glu.h> #include <stdio.h> #include <stdlib.h> SDL_Surface *screen; void quit( int code ) { SDL_Quit( ); /* Exit program. */ exit( code ); } void handleKeyEvent( SDL_keysym* keysym ) { switch( keysym->sym ) { case SDLK_ESCAPE: quit( 0 ); break; case SDLK_SPACE: break; default: break; } } void resizeGL(int width,int height) { if ( height == 0 ) { height = 1; } //Reset View glViewport( 0, 0, (GLint)width, (GLint)height ); //Choose the Matrix mode glMatrixMode( GL_PROJECTION ); //reset projection glLoadIdentity(); //set perspection gluPerspective( 45.0, (GLfloat)width/(GLfloat)height, 0.1, 100.0 ); //choose Matrix mode glMatrixMode( GL_MODELVIEW ); glLoadIdentity(); } void handleEvents() { // Our SDL event placeholder. SDL_Event event; //Grab all the events off the queue. while( SDL_PollEvent( &event ) ) { switch( event.type ) { case SDL_KEYDOWN: // Handle key Event handleKeyEvent( &event.key.keysym ); break; case SDL_QUIT: // Handle quit requests (like Ctrl-c). quit( 0 ); break; case SDL_VIDEORESIZE: //Handle resize event screen = SDL_SetVideoMode(event.resize.w, event.resize.h, 16, SDL_OPENGL|SDL_RESIZABLE); if ( screen ) { resizeGL(screen->w, screen->h); } break; } } } void initSDL(int width,int height,int bpp,int flags) { // First, initialize SDL's video subsystem. if( SDL_Init( SDL_INIT_VIDEO ) < 0 ) { fprintf( stderr, "Video initialization failed: %s\n", SDL_GetError( ) ); quit( 1 ); } atexit(SDL_Quit); //Set some Attribute of OpenGL in SDL SDL_GL_SetAttribute( SDL_GL_RED_SIZE, 5 ); SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE, 5 ); SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, 5 ); SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE, 16 ); SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 ); //Set the video mode screen= SDL_SetVideoMode( width, height, bpp,flags); if(!screen ) { fprintf( stderr, "Video mode set failed: %s\n",SDL_GetError( ) ); quit( 1 ); } resizeGL(screen->w, screen->h); //Set caption SDL_WM_SetCaption( "Sierpinski 2D", NULL ); } void renderGL() { // Clear the color and depth buffers. glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); // We don't want to modify the projection matrix. */ glMatrixMode( GL_MODELVIEW ); glLoadIdentity( ); // Move down the z-axis. glTranslatef( -20.0, -20.0, -60.0 ); //Draw a square /* A triangle */ GLfloat vertices[3][2]={{0.0,0.0},{25.0,50.0},{50.0,0.0}}; int i, j, k; srand(10); /* standard random number generator */ GLfloat p[2] ={7.5,5.0}; /* an arbitrary initial point inside traingle */ glClear(GL_COLOR_BUFFER_BIT); /* clear the window */ glBegin(GL_POINTS); /* compute and plots 5000 new points */ for( k=0; k<500000; k++) { j=rand()%3; /* pick a vertex at random */ /* Compute point halfway between selected vertex and old point */ p[0] = (p[0]+vertices[j][0])/2.0; p[1] = (p[1]+vertices[j][1])/2.0; /* plot new point */ glVertex2fv(p); } glEnd(); SDL_GL_SwapBuffers( ); } void initGL( int width, int height ) { float ratio = (float) width / (float) height; // Our shading model--Gouraud (smooth). glShadeModel( GL_SMOOTH ); // Set the clear color. glClearColor( 0, 0, 0, 0 ); // Setup our viewport. glViewport( 0, 0, width, height ); //Change to the projection matrix and set our viewing volume. glMatrixMode( GL_PROJECTION ); glLoadIdentity(); gluPerspective( 60.0, ratio, 1.0, 100.0 ); } int main( int argc, char* argv[] ) { // Dimensions of our window. int width = 640; int height = 480; // Color depth in bits of our window. int bpp = 32; int flags= SDL_OPENGL|SDL_RESIZABLE; //Set the SDL initSDL(width, height, bpp,flags); //Set the OpenGL initGL( width, height ); //main loop while(true) { /* Process incoming events. */ handleEvents( ); /* Draw the screen. */ renderGL( ); } return 0; }
三维
/***************************************************************************** Copyright: 2012, ustc All rights reserved. contact:[email protected] File name: main3D.c Description:Sierpinski 3D. Author:Silang Quan Version: 1.0 Date: 2012.12.02 *****************************************************************************/ #include <SDL/SDL.h> #include <GL/gl.h> #include <GL/glu.h> #include <stdio.h> #include <stdlib.h> SDL_Surface *screen; GLfloat colors[4][3]={{1.0,0.0,0.0},{0.0,1.0,0.0},{0.0,0.0,1.0},{0.0,1.0,1.0}}; void quit( int code ) { SDL_Quit( ); /* Exit program. */ exit( code ); } void handleKeyEvent( SDL_keysym* keysym ) { switch( keysym->sym ) { case SDLK_ESCAPE: quit( 0 ); break; case SDLK_SPACE: break; default: break; } } void resizeGL(int width,int height) { if ( height == 0 ) { height = 1; } //Reset View glViewport( 0, 0, (GLint)width, (GLint)height ); //Choose the Matrix mode glMatrixMode( GL_PROJECTION ); //reset projection glLoadIdentity(); //set perspection gluPerspective( 45.0, (GLfloat)width/(GLfloat)height, 0.1, 100.0 ); //choose Matrix mode glMatrixMode( GL_MODELVIEW ); glLoadIdentity(); } void handleEvents() { // Our SDL event placeholder. SDL_Event event; //Grab all the events off the queue. while( SDL_PollEvent( &event ) ) { switch( event.type ) { case SDL_KEYDOWN: // Handle key Event handleKeyEvent( &event.key.keysym ); break; case SDL_QUIT: // Handle quit requests (like Ctrl-c). quit( 0 ); break; case SDL_VIDEORESIZE: //Handle resize event screen = SDL_SetVideoMode(event.resize.w, event.resize.h, 16, SDL_OPENGL|SDL_RESIZABLE); if ( screen ) { resizeGL(screen->w, screen->h); } break; } } } void initSDL(int width,int height,int bpp,int flags) { // First, initialize SDL's video subsystem. if( SDL_Init( SDL_INIT_VIDEO ) < 0 ) { fprintf( stderr, "Video initialization failed: %s\n", SDL_GetError( ) ); quit( 1 ); } atexit(SDL_Quit); //Set some Attribute of OpenGL in SDL SDL_GL_SetAttribute( SDL_GL_RED_SIZE, 5 ); SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE, 5 ); SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, 5 ); SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE, 16 ); SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 ); //Set the video mode screen= SDL_SetVideoMode( width, height, bpp,flags); if(!screen ) { fprintf( stderr, "Video mode set failed: %s\n",SDL_GetError( ) ); quit( 1 ); } resizeGL(screen->w, screen->h); //Set caption SDL_WM_SetCaption( "Sierpinski 3D", NULL ); } void triangle( GLfloat *va, GLfloat *vb, GLfloat *vc) { glVertex3fv(va); glVertex3fv(vb); glVertex3fv(vc); } void tetra(GLfloat *a, GLfloat *b, GLfloat *c, GLfloat *d) { glColor3fv(colors[0]); triangle(a,b,c); glColor3fv(colors[1]); triangle(a,c,d); glColor3fv(colors[2]); triangle(a,d,b); glColor3fv(colors[3]); triangle(b,d,c); } void divide_tetra(GLfloat *a, GLfloat *b, GLfloat *c, GLfloat *d, int m) { GLfloat mid[6][3]; int j; if(m>0) { /* compute six midpoints */ for(j=0; j<3; j++) mid[0][j]=(a[j]+b[j])/2; for(j=0; j<3; j++) mid[1][j]=(a[j]+c[j])/2; for(j=0; j<3; j++) mid[2][j]=(a[j]+d[j])/2; for(j=0; j<3; j++) mid[3][j]=(b[j]+c[j])/2; for(j=0; j<3; j++) mid[4][j]=(c[j]+d[j])/2; for(j=0; j<3; j++) mid[5][j]=(b[j]+d[j])/2; /* create 4 tetrahedrons by subdivision */ divide_tetra(a,mid[0],mid[1],mid[2], m-1); divide_tetra(mid[0],b,mid[3],mid[5], m-1); divide_tetra(mid[1],mid[3],c,mid[4], m-1); divide_tetra(mid[2],mid[4],d,mid[5], m-1); } else tetra(a,b,c,d); /* draw tetrahedron at end of recursion */ } void renderGL() { //Define a triangle in space GLfloat v[4][3]={{0.0, 0.0, 1.0},{0.0, 0.942809, -0.33333},{-0.816497, -0.471405, -0.333333},{0.816497, -0.471405, -0.333333}}; // Clear the color and depth buffers. glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); // We don't want to modify the projection matrix. */ glMatrixMode( GL_MODELVIEW ); glLoadIdentity( ); // Move down the z-axis. glTranslatef( 0.0, 0.0, -2.0 ); glRotatef(50,0,1,0); glRotatef(30,1,0,0); glClear(GL_COLOR_BUFFER_BIT); /* clear the window */ glBegin(GL_TRIANGLES); divide_tetra(v[0],v[1],v[2],v[3],3); glEnd(); SDL_GL_SwapBuffers( ); } void initGL( int width, int height ) { float ratio = (float) width / (float) height; // Our shading model--Gouraud (smooth). glShadeModel( GL_SMOOTH ); // Set the clear color. glClearColor( 0, 0, 0, 0 ); // Setup our viewport. glViewport( 0, 0, width, height ); //Change to the projection matrix and set our viewing volume. glMatrixMode( GL_PROJECTION ); glLoadIdentity(); gluPerspective( 60.0, ratio, 1.0, 100.0 ); } int main( int argc, char* argv[] ) { // Dimensions of our window. int width = 640; int height = 480; // Color depth in bits of our window. int bpp = 32; int flags= SDL_OPENGL|SDL_RESIZABLE; //Set the SDL initSDL(width, height, bpp,flags); //Set the OpenGL initGL( width, height ); //main loop while(true) { /* Process incoming events. */ handleEvents( ); /* Draw the screen. */ renderGL( ); } return 0; }
参考:Sierpinski镂垫程序-http://www.codeforge.com/read/45707/Sierpinski%E9%95%82%E5%9E%AB%E7%A8%8B%E5%BA%8F.txt__html