所属主题: 技术根基 · NLP · CV · 数学 · 工程基础

分形图形递归实现:球体细分逼近与Sierpinski镂垫C++程序

计算机图形学分形算法C++实现,包含球体细分逼近程序(四面体递归细分)与Sierpinski镂垫程序(分形图形递归生成),附完整源码与运行结果。

Sierpinski镂垫是经典的分形图形,本文用C++递归实现三种Sierpinski镂垫绘制程序,介绍分形递归思想与计算机图形学绘制方法。

Sierpinski镂垫是一个非常有趣的图案,有着悠久的历史, 在分形几何中等领域里引起了人们极大地兴趣, 是用递归和随机方式定义的几何形状。

生成算法如下:

  1. 在三角形内部随机选取一个点作为初始点;
  2. 在三角形的3个顶点中随机选取一个,求出该顶点与初始点连线的中点,画出该中点;
  3. 将第二步中的中点作为初始点,循环第二步;

1 二维Sierpinski镂垫

代码

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
/*使用随机选择的顶点和中点绘制二维Sierpinski镂垫*/
#include <windows.h>
#include <GL/glut.h>

void myinit()
{
glClearColor(1.0,1.0,1.0,1.0);/*白色背景*/
glColor3f(1.0,0.0,0.0);/*红色*/

glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0.0,50.0,0.0,50.0);/*50×50相机坐标窗口与原点左下角*/
glMatrixMode(GL_MODELVIEW);

}

void display()
{
GLfloat vertices[3][2]={% raw %}{{0.0,0.0},{25.0,50.0},{50.0,0.0}}{% endraw %};

int j,k;
int rand();/*产生随机数*/
GLfloat p[2]={7.5,5.0};/*在三角形内任意初始点*/
glClear(GL_COLOR_BUFFER_BIT);/*清理窗口*/

glBegin(GL_POINTS);/*产生5000个新点*/

for(k=0;k<5000;k++)
{
j=rand()%3;/*随机选择一个顶点*/
/*计算点位于选定顶点和旧点之间*/
p[0]=(p[0]+vertices[j][0])/2.0;
p[1]=(p[1]+vertices[j][1])/2.0;
/*画新点*/
glVertex2fv(p);
}
glEnd();
glFlush();/*清除缓冲帧*/
}

int main(int argc,char *argv[])
{
glutInit(&argc,argv);/*标准的GLUT初始化*/
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);/*默认设置*/
glutInitWindowSize(500,500);/*500×500像素窗口*/
glutInitWindowPosition(0,0);/*将窗口放在左下角*/
glutCreateWindow("Sierpinski Gasket");/*窗口名*/
glutDisplayFunc(display);/*窗口打开时调用的显示回调*/
myinit();/*设置属性*/
glutMainLoop();/*进入事件循环*/
}

结果

2 生成 Sierpinski 镂垫的递归程序

代码

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
/* 通过细分三角形的方法生成Sierpinski镂垫 */
/* 通过命令行输入递归的次数 */
#include <GL/glut.h>
#include<stdlib.h>
/* 初始的三角形 */
GLfloat v[3][2]={% raw %}{{-1.0, -0.58}, {1.0, -0.58}, {0.0, 1.15}}{% endraw %};
int n;
void triangle( GLfloat *a, GLfloat *b, GLfloat *c)
/* 定义某个三角形 */
{
glVertex2fv(a);
glVertex2fv(b);
glVertex2fv(c);
}
void divide_triangle(GLfloat *a, GLfloat *b, GLfloat *c, int m)
{
/* 基于某个顶点的数量对三角形进行细分处理 */
GLfloat v0[2], v1[2], v2[2];
int j;
if(m>0)
{
for(j=0; j<2; j++) v0[j]=(a[j]+b[j])/2;
for(j=0; j<2; j++) v1[j]=(a[j]+c[j])/2;
for(j=0; j<2; j++) v2[j]=(b[j]+c[j])/2;
divide_triangle(a, v0, v1, m-1);
divide_triangle(c, v1, v2, m-1);
divide_triangle(b, v2, v0, m-1);
}
else triangle(a,b,c); /* 递归结束时绘制三角形 */
}
void display(void)
{
glClear(GL_COLOR_BUFFER_BIT);
glBegin(GL_TRIANGLES);
divide_triangle(v[0], v[1], v[2], n);
glEnd();
glFlush();
}
void myinit()
{
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(-2.0, 2.0, -2.0, 2.0);
glMatrixMode(GL_MODELVIEW);
glClearColor(1.0, 1.0, 1.0, 1.0);
glColor3f(0.0,0.0,0.0);
}
main(int argc, char **argv)
{
n=3; /* 或者在此输入三角形细分的步数 */
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutInitWindowSize(500, 500);
glutCreateWindow("Sierpinski Gasket");
glutDisplayFunc(display);
myinit();
glutMainLoop();
}

结果

3 三维 Sierpinski 镂垫的递归程序

代码

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
/* 通过递归细分四面体方法生成Sierpinski镂垫 */
/* 通过命令行递归的次数 */
#include <stdlib.h>
#include <GL/glut.h>
/* 初始的四面体 */
GLfloat v[4][3]={% raw %}{{0.0, 0.0, 1.0},{0.0, 0.942809, -0.33333},
{-0.816497, -0.471405, -0.333333},{0.816497, -0.471405, -0.333333}}{% endraw %};
GLfloat colors[4][3]={% raw %}{{1.0,0.0,0.0},{0.0,1.0,0.0},
{0.0,0.0,1.0},{0.0,0.0,0.0}}{% endraw %};
int n;
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)
{
/* 计算六个中点 */
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;
/* 通过细分生成四个四面体 */
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); /* 递归结束时绘制四面体 */
}
void display(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glBegin(GL_TRIANGLES);
divide_tetra(v[0],v[1],v[2],v[3],n);
glEnd();
glFlush();
}
void myReshape(int w, int h)
{
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if (w <= h)
glOrtho(-2.0, 2.0, -2.0 * (GLfloat) h / (GLfloat) w,
2.0 * (GLfloat) h / (GLfloat) w, -10.0, 10.0);
else
glOrtho(-2.0 * (GLfloat) w / (GLfloat) h,
2.0 * (GLfloat) w / (GLfloat) h, -2.0, 2.0, -10.0, 10.0);
glMatrixMode(GL_MODELVIEW);
glutPostRedisplay();
}
main(int argc, char **argv)
{
n=atoi(argv[1]); /* 或者在此处输入四面体细分的步数 */
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowSize(500, 500);
glutCreateWindow("3D Gasket");
glutReshapeFunc(myReshape);
glutDisplayFunc(display);
glEnable(GL_DEPTH_TEST);
glClearColor (1.0, 1.0, 1.0, 1.0);
glutMainLoop();
}

结果

Sierpinski 镂垫程序:分形图形递归实现

本文用C++通过四面体递归细分逼近球体表面,介绍多边形网格细分与计算机图形学中的几何逼近方法。

球体的细分逼近程序

通过递归细分四面体生成球体,三种显示模式:线性框、均匀着色,插值着色

代码

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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
/* 该程序在init()函数中还定义了材质和光源 */
/* mode 0 = 线性框, mode 1 = 均与着色,
mode 3 = 插值着色 */
#include <stdlib.h>
#include<math.h>
#include <GL/glut.h>
typedef float point[4];
/* 初始化四面体 */
point v[]={% raw %}{{0.0, 0.0, 1.0}, {0.0, 0.942809, -0.33333},
{-0.816497, -0.471405, -0.333333}, {0.816497, -0.471405, -0.333333}}{% endraw %};

GLfloat theta[] = {0.0,0.0,0.0};

int n;
int mode;
void triangle( point a, point b, point c)
/*利用GL_LINR_LOOP模式显示一个三角形的线性图,定义一个法向量用于均匀着色,
定义三个法向量用于插值着色*/
{
if (mode==0) glBegin(GL_LINE_LOOP);
else glBegin(GL_POLYGON);
if(mode==1) glNormal3fv(a);
if(mode==2) glNormal3fv(a);
glVertex3fv(a);
if(mode==2) glNormal3fv(b);
glVertex3fv(b);
if(mode==2) glNormal3fv(c);
glVertex3fv(c);
glEnd();
}
void normal(point p)
{
/* 矢量归一化 */
double sqrt(double d);
float d = 0.0;
int i;
for (i = 0; i < 3; i++) d += p[i] * p[i];
d = sqrt(d);
if (d > 0.0)
for (i = 0; i < 3; i++) p[i] /= d;
}
void divide_triangle(point a, point b, point c, int m)
{
/* 基于顶点数目细分三角形,应用右手规则生成对象的外向表面 */
point v1, v2, v3;
int j;
if(m>0)
{
for(j=0; j<3; j++) v1[j]=a[j]+b[j];
normal(v1);
for(j=0; j<3; j++) v2[j]=a[j]+c[j];
normal(v2);
for(j=0; j<3; j++) v3[j]=b[j]+c[j];
normal(v3);
divide_triangle(a, v1, v2, m-1);
divide_triangle(c, v2, v3, m-1);
divide_triangle(b, v3, v1, m-1);
divide_triangle(v1, v3, v2, m-1);
}
else triangle(a,b,c); /* 递归结束时绘制三角形 */
}

void tetrahedron(int m)
{
/* 对四面体的表面应用三角细分 */
divide_triangle(v[0], v[1], v[2], m);
divide_triangle(v[3], v[2], v[1], m);
divide_triangle(v[0], v[3], v[1], m);
divide_triangle(v[0], v[2], v[3], m);
}
void display()
{
/* 逐一显示这三种模式下的四面体 */
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
mode=0;
tetrahedron(n);
mode=1;
glTranslatef(-2.0, 0.0, 0.0);
tetrahedron(n);
mode=2;
glTranslatef(4.0, 0.0, 0.0);
tetrahedron(n);
glFlush();
}

void myReshape(int w, int h)
{
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if (w <= h)
glOrtho(-4.0, 4.0, -4.0 * (GLfloat) h / (GLfloat) w,
4.0 * (GLfloat) h / (GLfloat) w, -10.0, 10.0);
else
glOrtho(-4.0 * (GLfloat) w / (GLfloat) h,
4.0 * (GLfloat) w / (GLfloat) h, -4.0, 4.0, -10.0, 10.0);
glMatrixMode(GL_MODELVIEW);
display();
}
void myinit()
{
GLfloat mat_specular[]={1.0, 1.0, 1.0, 1.0};
GLfloat mat_diffuse[]={1.0, 1.0, 1.0, 1.0};
GLfloat mat_ambient[]={1.0, 1.0, 1.0, 1.0};
GLfloat mat_shininess={100.0};
GLfloat light_ambient[]={0.0, 0.0, 0.0, 1.0};
GLfloat light_diffuse[]={1.0, 1.0, 1.0, 1.0};
GLfloat light_specular[]={1.0, 1.0, 1.0, 1.0};
/* 为光源0分别设置环境光、漫反射光和镜面反射光的参数 */
glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient);
glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse);
glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular);
/* 为所有三角形正面定义材质属性 */
glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient);
glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
glMaterialf(GL_FRONT, GL_SHININESS, mat_shininess);
glShadeModel(GL_SMOOTH); /* 开启平滑着色 */
glEnable(GL_LIGHTING); /* 开启光照 */
glEnable(GL_LIGHT0); /* 开启光源0 */
glEnable(GL_DEPTH_TEST); /* 开启z-buffer */
glClearColor (1.0, 1.0, 1.0, 1.0);
glColor3f (0.0, 0.0, 0.0);
}
main(int argc, char **argv)
{
n=4;//n=1,2,3,4,5,6……
//n=atoi(argv[1]);//直接运行会出错,具体参照BookCode的此处源码处理方案
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowSize(500, 500);
glutCreateWindow("sphere");
myinit();
glutReshapeFunc(myReshape);
glutDisplayFunc(display);
glutMainLoop();
}

结果

本文结束 感谢您的阅读