关于C#:Sierpinsky金字塔递归算法

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坐标有问题:确实金字塔没有按我的意愿绘制:

Pyramid

但是,如果我使用 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;
}