1.基于打点的分形三角形
/* A1 Sierpinski Gasket Program 谢尔平斯基镂垫 */
/* gasket.c */
/* Two-Dimensional Sierpinski Gasket 谢尔平斯基镂垫 */
/* Generated Using Randomly Selected Vertices */
/* And Bisection */
///
//#include "stdafx.h"
#include <windows.h>
#include <gl\glut.h>
#include <gl\gl.h>
#include <gl\glu.h>
#pragma comment(lib,"opengl32.lib")
#pragma comment(lib,"glu32.lib")
#ifdef __APPLE__
#include <GLUT/glut.h>
#else
#include <GL\glut.h>
#endif
void myinit()
{
/* attributes */
glClearColor(1.0, 1.0, 1.0, 1.0); /* white background */
glColor3f(1.0, 0.0, 0.0); /* draw in red */
/* set up viewing */
/* 500 x 500 window with origin lower left */
glMatrixMode(GL_PROJECTION); // 与流水线对话,启动投影矩阵,指定投影矩阵的参数
glLoadIdentity();
gluOrtho2D(0.0, 50.0, 0.0, 50.0); // 50*50的2D投影平面空间
// 函数原型 0.0,(GLdouble)w,0.0,(GLdouble)h);
// gluOrtho2D(left,right,bottom,up)
// gluOrtho2D(x_mix, x_max, y_mix, y_max)
//(左下角x坐标,右上角x坐标,左下角y坐标,右上角y坐标)
// (0.0, 0.0) - (50.0, 50.0)
// (0.0, 0.0) - (150.0, 150.0) 投影平面空间越大,对象显示越小
glMatrixMode(GL_MODELVIEW);
}
void display(void)
{
GLfloat vertices[3][2] = { {0.0,0.0},{25.0,50.0},{50.0,0.0} };
// 二维点
// 3行2列
// 行下标 0 1 2
/* A triangle, 2D是3D的特例,内部表示都一样 */
int j, k;
int rand(); /* standard random number generator */
GLfloat p[2] = { 1,7.5 }; /* An arbitrary initial point inside traingle */
// 看看改变初始值,是否改变图形? 初始化第一个点不影响最终的分形结果
// 甚至初始化的点在三角形外面
// 该点不断第被更新,按照中点计算
glClear(GL_COLOR_BUFFER_BIT); /*clear the window */ // 用初始化中指定的颜色进行 白色 清屏
// 没有明确调用时候 情况下,用缺省 黑色 清屏
// 注释看看 没有明确调用 情况
/* compute and plots 5000 new points */
glBegin(GL_POINTS);//说明下面要画的图形是点
//基本思路就是:确定三角形的三个顶点,以及开始任意确定一个点,随机选取一个三角形的顶点,连接它与那个随机点,取中点
for (k = 0; k < 500000; k++) // 点数 请输入 50000 还行
// 50000000 有点费劲
{
j = rand() % 3; /* pick a vertex at random */
// 在 0 1 2 之间随机生成
// rand()是伪随机数生成函数,%是模运算,%3对3取余
/* Compute point halfway between selected vertex and old point */
p[0] = (p[0] + vertices[j][0]) / 2.0;
// p[0] 下标 0,对应x坐标
// j行0列 列下标 0,对应x坐标
p[1] = (p[1] + vertices[j][1]) / 2.0;
// p[1] 下标 0,对应y坐标
// j行1列 列下标 1,对应y坐标
/* plot new point */
glVertex2fv(p); //理解为向流水线发送数据
}
glEnd();
glFlush(); /* clear buffers */ //立即模式
}
void main(int argc, char** argv)
{
/* Standard GLUT initialization */
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB); /* default, not needed */
glutInitWindowSize(500, 500); /* 500 x 500 pixel window */
glutInitWindowPosition(0, 0); /* place window top left on display */
glutCreateWindow("Sierpinski Gasket 2013-2019 WHU"); /* window title */
glutDisplayFunc(display); /* display callback invoked when window opened */
myinit(); /* set attributes */
glutMainLoop(); /* enter event loop */
}
2.基于递归的分形三角形
```cpp
/* A2 recursive generation of Sierpinski gasket */
/* recursive subdivision of triangle to form Sierpinski gasket */
/* number of recursive steps given on command line */
/* gasket2.c */
///
#include <stdio.h>
#include <stdlib.h>
#ifdef __APPLE__
#include <GLUT/glut.h>
#else
#include <GL/glut.h>
#endif
#pragma comment(lib,"glut32.lib")
// #include <gl\gl.h>
// #include <gl\glu.h>
//
// #pragma comment(lib,"opengl32.lib")
// #pragma comment(lib,"glu32.lib")
/* initial triangle */
GLfloat v[3][2] = { {-1.0, -0.58}, {1.0, -0.58}, {0.0, 1.15} }; // 全局二维数组存储空间,按照次序,存放浮点数
// 二维数组本质上是以数组作为数组元素的数组,即“数组的数组”
// [3][2] 表示3行2列的二维数组,连续存放的三个2列数组
int n; // 全局变量 递归层次
void triangle(GLfloat *a, GLfloat *b, GLfloat *c)
/* specify one triangle */
{
glVertex2fv(a);
glVertex2fv(b);
glVertex2fv(c);
}
//分形函数(递归调用)
void divide_triangle(GLfloat *a, GLfloat *b, GLfloat *c, int m)
{
/* triangle subdivision using vertex numbers */
//临时的点用来储存中点
GLfloat v0[2], v1[2], v2[2]; // 局部,三个独立的一维数组,2列一维数组,分别对应x,y坐标
int j;
if (m > 0) // n 演示输入 0 ,1,2,3 看看效果如何
{
//每一个循环计算的是点的横纵坐标
for (j = 0; j < 2; j++) v0[j] = (a[j] + b[j]) / 2; //计算当前边的中点的x,y坐标,for 循环
for (j = 0; j < 2; j++) v1[j] = (a[j] + c[j]) / 2; //计算当前边的中点的x,y坐标,for 循环
for (j = 0; j < 2; j++) v2[j] = (b[j] + c[j]) / 2; //计算当前边的中点的x,y坐标,for 循环
divide_triangle(a, v0, v1, m - 1); // 递归调用 recursion 原来一个顶点加上新生成的二个顶点
// 数组名是常量指针类型,并且是数组的首地址
divide_triangle(c, v1, v2, m - 1); //递归调用 recursion 递归层次减一
// 数组名是常量指针类型,并且是数组的首地址
divide_triangle(b, v2, v0, m - 1); //递归调用 recursion
// 数组名是常量指针类型,并且是数组的首地址
}
else triangle(a, b, c); /* draw triangle at end of recursion */ //最终递归分解的结果
}
void display()
{
glClear(GL_COLOR_BUFFER_BIT);
//Efficiency Note程序效率 the glBegin and glEnd in the display callback rather than in the function triangle
//Efficiency Note程序效率 GL_TRIANGLES rather than GL_POLYGON
glColor3f(1.0, 0.0, 0.0); //设置流水线颜色状态
glBegin(GL_TRIANGLES); // 指定渲染三角形,
divide_triangle(v[0], v[1], v[2], n); // n 递归次数 前三个参数指代的是最外面的三角形的三个顶点
// 数组名是常量指针类型
// 全局二维数组 GLfloat v[3][2], 表示的二维数组是3行2列的
// 表示 三个 连续存放的 一维数组(每个数组都2列)
// 每个一维数组首地址,就是 该一维数组名字
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); //前景黑色,三角形
}
int main(int argc, char **argv)
{
//argc即argument count,指代传入main函数的参数个数,由于第一个参数一定是argv[0](程序的路径名称)
//所以,真正输入的参数个数为argc-1个
if (argc < 2)//这里的分支语句就是在输入之前判断有没有提前传入参数
{
printf("Please input number of subdivision steps(less than 16) \"n\" \n Or Re-run again and Type number \"n\" following after Program name:\n");
scanf_s("%d", &n);//scanf这里在vs2017报错,需要改成scanf_s 全局变量 递归层次
// read number of subdivision steps from keyboard typing
}
else {
n = atoi(argv[1]); // 把字符串转换成整型数
}
if (n > 16)//控制递归层次
{
printf("The number of dividing \"n\" less than 16 is preferred for illustrating! \n");
exit(-1);
}
// n=7; //
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutInitWindowSize(500, 500);
glutCreateWindow("Sierpinski Gasket");
glutDisplayFunc(display);
myinit();
glutMainLoop();
}
3.由四个分形三角形拼接而成的四面体
```cpp
/* A3 ?? tetra.c */
/* Recursive subdivision of tetrahedron to form 3D Sierpinski gasket */
/* divide_triangle */
// #include <gl\gl.h>
// #include <gl\glu.h>
// #pragma comment(lib,"opengl32.lib")
// #pragma comment(lib,"glu32.lib")
#include <stdlib.h>
#ifdef __APPLE__
#include <GLUT/glut.h>
#else
#include <GL/glut.h>
#endif
#pragma comment(lib,"glut32.lib")
typedef float point[3]; // 自定义点类型 一维数组3列 3个元素 对应三个坐标点x,y,z
/* initial tetrahedron */
point v[] = { {0.0, 0.0, 1.0}, {0.0, 0.942809, -0.33333},
{-0.816497, -0.471405, -0.333333}, {0.816497, -0.471405, -0.333333} };
// point的数组,“数组的数组”
// 4行3列
static GLfloat theta[] = { 0.0,0.0,0.0 }; //
int n;
//三角形绘制函数
void triangle(point a, point b, point c)
/* display one triangle using a line loop for wire frame, a single
normal for constant shading, or three normals for interpolative shading */
{
glBegin(GL_POLYGON);
glNormal3fv(a); // 面需要方向,指定一个方向,这里相当于是设置法向量
glVertex3fv(a);
glVertex3fv(b);
glVertex3fv(c);
glEnd();
}
//对于每一个大三角形的递归分型,这个函数可以完成一个面的分型,m为递归深度
void divide_triangle(point a, point b, point c, int m) // 形参 自定义的数组变量 point
{
/* triangle subdivision using vertex numbers
righthand rule applied to create outward pointing faces */
point v1, v2, v3; // 局部 变量 自定义的数组变量 point
int j;
if (m > 0)
{
for (j = 0; j < 3; j++) v1[j] = (a[j] + b[j]) / 2; // 每个点 for循环 三个坐标x,y,z 计算出中点
for (j = 0; j < 3; j++) v2[j] = (a[j] + c[j]) / 2; // 每个点 for循环 三个坐标x,y,z 计算出中点
for (j = 0; j < 3; j++) v3[j] = (b[j] + c[j]) / 2; // 每个点 for循环 三个坐标x,y,z 计算出中点
divide_triangle(a, v1, v2, m - 1); // 原来的一个顶点+二个中点,构成一个新三角形 递归分解
divide_triangle(c, v2, v3, m - 1); // 原来的一个顶点+二个中点,构成一个新三角形 递归分解
divide_triangle(b, v3, v1, m - 1); // 原来的一个顶点+二个中点,构成一个新三角形 递归分解
}
else(triangle(a, b, c)); /* draw triangle at end of recursion */
}
void tetrahedron(int m)//构建四面体
{
/* Apply triangle subdivision to faces of tetrahedron */
glColor3f(1.0, 0.0, 0.0); // 红
divide_triangle(v[0], v[1], v[2], m); // 全局变量 v 4行3列 4个点 构成 4面体 一共4个面,其中3个点构成一个面
glColor3f(0.0, 1.0, 0.0); // 绿
divide_triangle(v[3], v[2], v[1], m); // 全局变量 v 4行3列 4个点 构成 4面体 一共4个面,其中3个点构成一个面
glColor3f(0.0, 0.0, 1.0); // 蓝
divide_triangle(v[0], v[3], v[1], m); // 全局变量 v 4行3列 4个点 构成 4面体 一共4个面,其中3个点构成一个面
glColor3f(0.0, 0.0, 0.0); // 黑
divide_triangle(v[0], v[2], v[3], m); // 全局变量 v 4行3列 4个点 构成 4面体 一共4个面,其中3个点构成一个面
}
void display(void)
{
glMatrixMode(GL_MODELVIEW);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //配合 3 深度测试去掉 效果 与 glEnable(GL_DEPTH_TEST);
//glClear(GL_COLOR_BUFFER_BIT); // 配合 3 去掉GL_DEPTH_BUFFER_BIT看看效果 与 glEnable(GL_DEPTH_TEST);
// 尽管main函数初始化深度测试功能,但是深度buffer没有正确初始化,
// 当然就不能正确测试遮挡关系,也就不能争取显示
glLoadIdentity();
tetrahedron(n);
glFlush();
glMatrixMode(GL_MODELVIEW);
glutPostRedisplay();//重新绘制
}
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); //---〉mydisplay 避免显示排序问题
glutPostRedisplay();//重新绘制
}
void main(int argc, char **argv)
{
n = 3; //递归的次数--演示1,修改n, 0 - 5
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH); // 配合 1 与 glEnable(GL_DEPTH_TEST); 配合
//glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB); // 配合1 去掉GLUT_DEPTH看看效果, 与 glEnable(GL_DEPTH_TEST); 配合
glutInitWindowSize(500, 500);
glutCreateWindow("3D Gasket");
//glutReshapeFunc(myReshape); ///形状回调 注释看看不同效果 2017,为了设置窗口相应的参数
glutDisplayFunc(display);//绘制
glEnable(GL_DEPTH_TEST); //配合2 深度测试去掉 效果 与 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);配合
glClearColor(1.0, 1.0, 1.0, 1.0); //背景色,白色
glutMainLoop();
}
4.分形四面体
/* A3 gasket3.c */
/* recursive subdivision of a tetrahedron to form 3D Sierpinski gasket */
/* number of recursive steps given on command line */
#include <stdlib.h>
#include <stdio.h>
#ifdef __APPLE__
#include <GLUT/glut.h>
#else
#include <GL/glut.h>
#endif
/* initial tetrahedron */
GLfloat v[4][3] = { {0.0, 0.0, 1.0}, {0.0, 0.942809, -0.33333},
{-0.816497, -0.471405, -0.333333}, {0.816497, -0.471405, -0.333333} };
GLfloat colors[4][3] = { {1.0, 0.0, 0.0}, {0.0, 1.0, 0.0},
{0.0, 0.0, 1.0}, {0.0, 0.0, 0.0} };
int n;
void init()
{
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);
}
//以下为三层调用:三角形=>四面体=>分形四面体
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]); //R 色绘制
triangle(a, b, c);
glColor3fv(colors[1]); //G 色绘制
triangle(a, c, d);
glColor3fv(colors[2]); //B 色绘制
triangle(a, d, b);
glColor3fv(colors[3]); //0 黑色绘制 背面为黑色 看不到 消隐效果
triangle(b, d, c);
}
void divide_tetra(GLfloat *a, GLfloat *b, GLfloat *c, GLfloat *d, int m)
{
GLfloat mid[6][3]; //6行3列,6个三维点,每个三维点3个坐标值x,y,z
int j;
if (m > 0)
{
/* compute six midpoints */ // 4面体 6个边 6个中点
for (j = 0; j < 3; j++) mid[0][j] = (a[j] + b[j]) / 2; // for 循环,0 1 2 对应 x y z
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;
/* create 4 tetrahedrons by subdivision */ // 一个4面体 子分为 4个四面体
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)); /* draw tetrahedron at end of recursion */ //最终不能分解为止,基本单元为4面体
}
void display()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//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();//标记当前的窗口需要重新绘制
}
int main(int argc, char **argv)
{
if (argc < 2)
{
printf("Please input number of subdivision steps(less than 16) \"n\" \n Or Re-run again and Type number \"n\" following after Program name:\n");
scanf_s("%d", &n); // read number of subdivision steps from keyboard typing
}
else {
n = atoi(argv[1]); // or set number of subdivision steps here
}
if (n > 16)
{
printf("The number of dividing \"n\" less than 16 is preferred for illustrating! \n");
exit(-1);
}
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH); 注释去掉 GLUT_DEPTH 看看 不同效果
//glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB ); //注释去掉 GLUT_DEPTH 看看 不同效果
glutInitWindowSize(500, 500);
glutCreateWindow("3D Gasket");
glutDisplayFunc(display);
glutReshapeFunc(myReshape); ///形状回调 注释看看不同效果
init();
glEnable(GL_DEPTH_TEST); ///看看注释 不同效果
//深度测试去掉 效果 与 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);配合
glClearColor(1.0, 1.0, 1.0, 1.0);
glutMainLoop();
}