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();
}