标签:
做好了CHAIKIN细分曲线之后,我着手做DOO-SABIN细分曲面,这是细分曲面中最简单的例子,本来以为很容易就能实现,后来发现自己真的是弱的可以,另外补充一下,充分意识到数据结构的用处,比如利用点边面表储存信息的时候,才可以知道哪些边组成了面,哪个面由哪几个边组成
现在是通过点表、边表以及面表储存
现在仅仅是简单的把正方体细分了一次。。而且面表还没有储存就已经复杂成下面这个熊样了。。感觉这么做不是那么回事
#include<GL/GLUT.H> #include <windows.h> #include <math.h> #include <gl/GL.h> #define MAXVEX 1000 //最大顶点数 //点表 static const GLfloat vertex_list[][3] = { -0.5f, -0.5f, -0.5f,//0 0.5f, -0.5f, -0.5f,//1 0.5f, 0.5f, -0.5f,//2 -0.5f, 0.5f, -0.5f,//3 -0.5f, -0.5f, 0.5f,//4 0.5f, -0.5f, 0.5f,//5 0.5f, 0.5f, 0.5f,//6 -0.5f, 0.5f, 0.5f,//7 }; //边表 static const GLint line_list[][2] = { 0, 1,//0 0, 3,//1 0, 4,//2 1, 2,//3 1, 5,//4 2, 3,//5 2, 6,//6 3, 7,//7 4, 5,//8 4, 7,//9 5, 6,//10 6, 7,//11 }; //面表 static const GLint face_list[][4] = { 0, 3, 5, 1,//bottem 2, 1, 7, 9,//left 5, 6, 11, 7,//front 3, 4, 10, 6,//right 0, 4, 8, 2,//back 8, 9, 11, 10,//top }; template <class T> int getArrayLen(T& array) { return (sizeof(array) / sizeof(array[0])); } //新细分点的初始化 int V = getArrayLen(vertex_list); int L = getArrayLen(line_list); int F = getArrayLen(face_list); GLfloat vertex_listn[MAXVEX][3]; GLint line_listn[MAXVEX][2]; GLint face_listn[MAXVEX][2]; void myDisplay(void){ glClear(GL_COLOR_BUFFER_BIT); glRotatef(45, 1, 1, 1); //计算新的点数 int Np = 0;//Number of points for (int i = 0; i < F; i++)//一共F个面 { int NF = getArrayLen(face_list[i]);//第i个面上有几个点,边数和点数是一样的 float fc[1][3] = {0.0,0.0,0.0};//定义面点 face point //计算新面点 for (int j = 0; j < NF; j++) { for (int u = 0; u < 3; u++) { fc[0][u] = fc[0][u] + vertex_list[line_list[face_list[i][j]][0]][u]; fc[0][u] = fc[0][u] + vertex_list[line_list[face_list[i][j]][1]][u]; } } for (int u = 0; u < 3; u++) { fc[0][u] = fc[0][u]/(2*NF);//因为每个点被计算了两遍 } //至此新面点坐标为fc //计算边点 for (int j = 0; j < NF; j++) { //第j条边和第j+1条边是相邻的,这在一开始的表里就是成立的 float lc1[1][3] = { 0.0, 0.0, 0.0 }; float lc2[1][3] = { 0.0, 0.0, 0.0 }; int x, y, z;//在j条和j+1边上一共有4个点。其中两个是一样的,就是两条线的交点,用x表示交点 if (j != NF - 1) { if (line_list[face_list[i][j]][0] == line_list[face_list[i][j+1]][0]) { x = line_list[face_list[i][j]][0]; y = line_list[face_list[i][j]][1]; z = line_list[face_list[i][j+1]][1]; } else if (line_list[face_list[i][j]][0] == line_list[face_list[i][j+1]][1]) { x = line_list[face_list[i][j]][0]; y = line_list[face_list[i][j]][1]; z = line_list[face_list[i][j + 1]][0]; } else if (line_list[face_list[i][j]][1] == line_list[face_list[i][j + 1]][0]) { x = line_list[face_list[i][j]][1]; y = line_list[face_list[i][j]][0]; z = line_list[face_list[i][j + 1]][1]; } else{ x = line_list[face_list[i][j]][1]; y = line_list[face_list[i][j]][0]; z = line_list[face_list[i][j + 1]][0]; } } else//此时是最后一条边和第一条边 { if (line_list[face_list[i][j]][0] == line_list[face_list[i][0]][0]) { x = line_list[face_list[i][j]][0]; y = line_list[face_list[i][j]][1]; z = line_list[face_list[i][0]][1]; } else if (line_list[face_list[i][j]][0] == line_list[face_list[i][0]][1]) { x = line_list[face_list[i][j]][0]; y = line_list[face_list[i][j]][1]; z = line_list[face_list[i][0]][0]; } else if (line_list[face_list[i][j]][1] == line_list[face_list[i][0]][0]) { x = line_list[face_list[i][j]][1]; y = line_list[face_list[i][j]][0]; z = line_list[face_list[i][0]][1]; } else{ x = line_list[face_list[i][j]][1]; y = line_list[face_list[i][j]][0]; z = line_list[face_list[i][0]][0]; } } //计算两个边点 for (int u = 0; u < 3; u++) { lc1[0][u] = (vertex_list[x][u] + vertex_list[y][u]) / 2; lc2[0][u] = (vertex_list[x][u] + vertex_list[z][u]) / 2; } for (int u = 0; u < 3; u++) { vertex_listn[Np][u] = (lc1[0][u] + lc2[0][u] + fc[0][u] + vertex_list[x][u])/4; } Np++; } } //以上部分为计算新顶点,点表搞定 //最后一步的时候的NP表示有[Np-1]++个新点,也就是说新的点数为Np //一下开始搞新边表 //其实也就分为两类,就是新面边和新边边,在以前同个面上的点连接起来的叫新面边,在以前两个面上的点连接起来的是新边边 //先存储新面边 int Nl=0; for (int i = 0; i < F; i++)//一共F个面 { int NF = getArrayLen(face_list[i]);//第i个面上有几个点,边数和点数是一样的 for (int j = 0; j < NF; j++) { if (j != NF - 1) { line_listn[Nl][0] = Nl; line_listn[Nl][1] = Nl + 1; Nl++; } if (j == NF - 1) { line_listn[Nl][0] = Nl; line_listn[Nl][1] = Nl + 1-NF; Nl++; } } } int PPPP = Nl; //再存储新边边 for (int i = 0; i < L; i++)//一共L条边 { int x, y;//用来储存与边i相邻的两个面 int m, n;//用来储存i在x,y,面中是第几条边 for (int j = 0; j < F; j++)//一共F个面) { int NF = getArrayLen(face_list[j]);//第i个面上有几个点,边数和点数是一样的 for (int t = 0; t < NF; t++) { if (face_list[j][t] == i) { x = j; m = t; goto S1;//跳出两层循环 } } } S1:; for (int j = x + 1; j < F; j++)//一共F个面) { int NF = getArrayLen(face_list[j]);//第i个面上有几个点,边数和点数是一样的 for (int t = 0; t < NF; t++) { if (face_list[j][t] == i) { y = j; n = t; goto S2; } } } S2:; //至此记录下了边i的两个临近面为x和y,分别是第m和n条 //下一步需要找到 //判断这条边连接的两个面的顺时针还是,如果m面的l是从点0->1,n面也是的话为真,n面不是的话为假 int fn1; int fn2;//用来记录在面中所选面的下一个边的号 int NF = getArrayLen(face_list[x]); if (m != NF - 1) { fn1=face_list[x][m+1]; } else { fn1 = face_list[x][0]; } NF = getArrayLen(face_list[y]); if (n != NF - 1) { fn2 = face_list[y][n + 1]; } else { fn2 = face_list[y][0]; } //至此,fn1和fn2储存着边i在两个面上的下一条边的号码 //判断三条边fn1,fn2,和i是否相交于一点 float vertex1[1][3];//将这一点记为vertex,这里只管x坐标,x坐标可以控制三个顶点 //找到前两条线的交点,横坐标为vertex if (vertex_list[line_list[i][0]] == vertex_list[line_list[fn1][0]]) { vertex1[0][0] = vertex_list[line_list[i][0]][0]; vertex1[0][1] = vertex_list[line_list[i][0]][1]; vertex1[0][2] = vertex_list[line_list[i][0]][2]; } else if (vertex_list[line_list[i][1]] == vertex_list[line_list[fn1][0]]) { vertex1[0][0] = vertex_list[line_list[i][1]][0]; vertex1[0][1] = vertex_list[line_list[i][1]][1]; vertex1[0][2] = vertex_list[line_list[i][1]][2]; } else if (vertex_list[line_list[i][1]] == vertex_list[line_list[fn1][1]]) { vertex1[0][0] = vertex_list[line_list[i][1]][0]; vertex1[0][1] = vertex_list[line_list[i][1]][1]; vertex1[0][2] = vertex_list[line_list[i][1]][2]; } else if (vertex_list[line_list[i][0]] == vertex_list[line_list[fn1][1]]) { vertex1[0][0] = vertex_list[line_list[i][0]][0]; vertex1[0][1] = vertex_list[line_list[i][0]][1]; vertex1[0][2] = vertex_list[line_list[i][0]][2]; } //判断三条边fn1,fn2,和i是否相交于一点 float vertex2[1][3];//将这一点记为vertex,这里只管x坐标,x坐标可以控制三个顶点 //找到前两条线的交点,横坐标为vertex if (vertex_list[line_list[i][0]] == vertex_list[line_list[fn2][0]]) { vertex2[0][0] = vertex_list[line_list[i][0]][0]; vertex2[0][1] = vertex_list[line_list[i][0]][1]; vertex2[0][2] = vertex_list[line_list[i][0]][2]; } else if (vertex_list[line_list[i][1]] == vertex_list[line_list[fn2][0]]) { vertex2[0][0] = vertex_list[line_list[i][1]][0]; vertex2[0][1] = vertex_list[line_list[i][1]][1]; vertex2[0][2] = vertex_list[line_list[i][1]][2]; } else if (vertex_list[line_list[i][1]]== vertex_list[line_list[fn2][1]]) { vertex2[0][0] = vertex_list[line_list[i][1]][0]; vertex2[0][1] = vertex_list[line_list[i][1]][1]; vertex2[0][2] = vertex_list[line_list[i][1]][2]; } else if (vertex_list[line_list[i][0]][0] == vertex_list[line_list[fn2][1]][0]) { vertex2[0][0] = vertex_list[line_list[i][0]][0]; vertex2[0][1] = vertex_list[line_list[i][0]][1]; vertex2[0][2] = vertex_list[line_list[i][0]][2]; } //判读fn2经过x吗 int ifcross=0; if (vertex1[0][0] == vertex2[0][0] && vertex1[0][1] == vertex2[0][1] && vertex1[0][2] == vertex2[0][2]) { ifcross=1;//三直线交于一点为1 } else { ifcross = 0;//三直线不交于一点为0 } int p1, p2, p3, p4; //x面m边对应的点编号为p1,p2;y面n边为p3,p4 //计算这条边对应的两个面上各两个点的编号 int np = 0;//记述当前点的编号 for (int j = 0; j < x; j++) { int NF = getArrayLen(face_list[j]);//第i个面上有几个点,边数和点数是一样的 for (int u = 0; u < NF; u++) { np++; } } NF = getArrayLen(face_list[x]);//第x个面上有几个点,边数和点数是一样的 if (m == 0) { p1 = np + NF - 1; p2 = np; } else { p1 = np + m - 1; p2 = np + m; } np = 0; for (int j = 0; j < y; j++) { int NF = getArrayLen(face_list[j]);//第i个面上有几个点,边数和点数是一样的 for (int u = 0; u < NF; u++) { np++; } } NF = getArrayLen(face_list[y]);//第x个面上有几个点,边数和点数是一样的 if (n == 0) { p3 = np + NF - 1; p4 = np; } else { p3 = np + n - 1; p4 = np + n; } if (ifcross == 1) { line_listn[Nl][0] = p1; line_listn[Nl][1] = p3; Nl++; line_listn[Nl][0] = p2; line_listn[Nl][1] = p4; Nl++; } else { line_listn[Nl][0] = p1; line_listn[Nl][1] = p4; Nl++; line_listn[Nl][0] = p2; line_listn[Nl][1] = p3; Nl++; } } for (int i = 0; i < L; ++i) // 有L个面,循环L次 { glBegin(GL_LINES); {glVertex3fv(vertex_list[line_list[i][0]]);//其中每条边由两点组成 glVertex3fv(vertex_list[line_list[i][1]]); } glEnd(); } //绘制新边 glPointSize(3); glColor3f(1.0, 0.0, 0.0); for (int i = 0; i < Np; ++i) // 有L个面,循环L次 { glBegin(GL_POINTS); { glVertex3fv(vertex_listn[i]); } glEnd(); } for (int i = 0; i < Nl; ++i) // 有L个面,循环L次 { glBegin(GL_LINES); {glVertex3fv(vertex_listn[line_listn[i][0]]);//其中每条边由两点组成 glVertex3fv(vertex_listn[line_listn[i][1]]); } glEnd(); } glFlush(); } int main(int argc, char *argv[]) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE); glutInitWindowPosition(100, 100); glutInitWindowSize(400, 400); glutCreateWindow("opengl1"); glutDisplayFunc(&myDisplay); glutMainLoop(); return 0; }
效果还是可以的,如果有空的话我打算把面表和几次都写了
现在先放下暂时效果
标签:
原文地址:http://blog.csdn.net/lafengxiaoyu/article/details/51344727