我正在尝试实施一个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坐标有问题:实际上金字塔没有按照我想要的方式绘制:
但是,如果我使用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]);
}
}
}
我没有弄到什么问题。
答案 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;
}