Sierpinski金字塔递归算法

时间:2012-11-18 18:46:33

标签: c opengl glut

我正在尝试实施一个Sierpinsky金字塔,就像一个Sierpinsky三角形,但是在3D中。 我有这个结构来包含有关金字塔的所有数据:

typedef struct
{
    GLfloat xUp;
    GLfloat yUp;
    GLfloat zUp;
    GLfloat base;
    GLfloat height;
}pyramid;

然后我编写了一个计算三个子金字塔的函数:

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坐标有问题:实际上金字塔没有按照我想要的方式绘制:

Pyramid

但是,如果我使用glOrtho而不是gluPerspective,金字塔就会被绘制好。我知道gluPerspective和我使用的函数是正确的,但算法是错误的。
这是我实现计算所有子金字塔的算法的地方:

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 个答案:

答案 0 :(得分:1)

试一试:

// 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;
}