Sierpinsky pyramid recursive algorithm
我正在尝试实现一个谢尔宾斯基金字塔,它类似于谢尔宾斯基三角形,但是是 3D 的。
我有这个结构来包含有关金字塔的所有数据:
1 2 3 4 5 6 7 8 | typedef struct { GLfloat xUp; GLfloat yUp; GLfloat zUp; GLfloat base; GLfloat height; }pyramid; |
然后我写了一个计算三个子金字塔的函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | void findSubPyramids( pyramid pyr, pyramid subs[3]) { for(int i=0; i<3; i++) { subs[i].height=pyr.height/2.0; subs[i].base=pyr.base/2.0; } memcpy(subs,&pyr,3*sizeof(GLfloat)); subs[1].yUp= pyr.yUp-pyr.height/2.0; subs[1].xUp= pyr.xUp+pyr.base/4.0; subs[1].zUp= pyr.zUp-pyr.base/4.0; subs[2].yUp= subs[1].yUp; subs[2].xUp= pyr.xUp-pyr.base/4.0; subs[2].zUp= subs[1].zUp; } |
但是这个算法实现是错误的:底部两个子金字塔的zUp坐标有问题:确实金字塔没有按我的意愿绘制:
但是,如果我使用 glOrtho 而不是 gluPerspective,则可以绘制金字塔。我知道我使用的 gluPerspective 和函数是正确的,但是算法是错误的。
这是我实现计算所有子金字塔的算法的地方:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | void drawSierpinskyPyramid (pyramid pyr) { assert(EQUAL(pyr.height, pyr.base)); if(pyr.base > 4.0) { setRandomColor(); pyramid subs[3]; drawPyramid(pyr); findSubPyramids(pyr, subs); for(int i=0; i<3; i++) { drawSierpinskyPyramid(subs[i]); } } } |
我不明白出了什么问题。
试一试:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 | // gcc -std=c99 main.c -lglut -lGL -lGLU #include <GL/glut.h> #include <math.h> #include <stdlib.h> typedef struct { float x, y, z; } Vec3f; void glTriangle( Vec3f* v0, Vec3f* v1, Vec3f* v2 ) { glColor3ub( rand() % 255, rand() % 255, rand() % 255 ); glVertex3fv( (GLfloat*)v0 ); glVertex3fv( (GLfloat*)v1 ); glVertex3fv( (GLfloat*)v2 ); } // v0, v1, v2 = base, v3 = top void glTetrahedron( Vec3f* v0, Vec3f* v1, Vec3f* v2, Vec3f* v3 ) { glTriangle( v0, v2, v1 ); glTriangle( v0, v1, v3 ); glTriangle( v1, v2, v3 ); glTriangle( v2, v0, v3 ); } Vec3f Lerp( Vec3f* v0, Vec3f* v1, float u ) { Vec3f ret = { v0->x + ( v1->x - v0->x ) * u, v0->y + ( v1->y - v0->y ) * u, v0->z + ( v1->z - v0->z ) * u, }; return ret; } void glSierpinskiPyramid( Vec3f* v0, Vec3f* v1, Vec3f* v2, Vec3f* v3, unsigned int level ) { if( level == 0 ) { glTetrahedron( v0, v1, v2, v3 ); return; } // midpoints Vec3f m01 = Lerp( v0, v1, 0.5 ); Vec3f m12 = Lerp( v1, v2, 0.5 ); Vec3f m02 = Lerp( v0, v2, 0.5 ); Vec3f m03 = Lerp( v0, v3, 0.5 ); Vec3f m13 = Lerp( v1, v3, 0.5 ); Vec3f m23 = Lerp( v2, v3, 0.5 ); glSierpinskiPyramid( v0, &m01, &m02, &m03, level-1 ); glSierpinskiPyramid( &m01, v1, &m12, &m13, level-1 ); glSierpinskiPyramid( &m02, &m12, v2, &m23, level-1 ); glSierpinskiPyramid( &m03, &m13, &m23, v3, level-1 ); } void display() { glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); glMatrixMode( GL_PROJECTION ); glLoadIdentity(); double w = glutGet( GLUT_WINDOW_WIDTH ); double h = glutGet( GLUT_WINDOW_HEIGHT ); gluPerspective( 60, w / h, 0.1, 100 ); glMatrixMode( GL_MODELVIEW ); glLoadIdentity(); glTranslatef( 0, 0, -9 ); srand(0); glPushMatrix(); glScalef( 3, 3, 3 ); static float angle = 0; angle += 1; glRotatef( angle/3, 0.2, 1, 0 ); Vec3f v0 = { -1, -1 / sqrtf(3), -1 / sqrtf(6) }; Vec3f v1 = { 1, -1 / sqrtf(3), -1 / sqrtf(6) }; Vec3f v2 = { 0, 2 / sqrtf(3), -1 / sqrtf(6) }; Vec3f v3 = { 0, 0, 3 / sqrtf(6) }; glBegin( GL_TRIANGLES ); glSierpinskiPyramid( &v0, &v1, &v2, &v3, 3 ); glEnd(); glPopMatrix(); glutSwapBuffers(); } void timer(int extra) { glutPostRedisplay(); glutTimerFunc(16, timer, 0); } int main( int argc, char **argv ) { glutInit( &argc, argv ); glutInitDisplayMode( GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE ); glutInitWindowSize( 640, 480 ); glutCreateWindow("Sierpinski Pyramid" ); glutDisplayFunc( display ); glutTimerFunc(0, timer, 0); glEnable( GL_DEPTH_TEST ); glEnable( GL_CULL_FACE ); glutMainLoop(); return 0; } |