DOO-SABIN 细分正方体(1)利用邻接矩阵表示

来源:互联网 发布:手机贴纸淘宝 编辑:程序博客网 时间:2024/04/30 18:43

做好了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,//00.5f, -0.5f, -0.5f,//10.5f, 0.5f, -0.5f,//2-0.5f, 0.5f, -0.5f,//3-0.5f, -0.5f, 0.5f,//40.5f, -0.5f, 0.5f,//50.5f, 0.5f, 0.5f,//6-0.5f, 0.5f, 0.5f,//7};//边表static const GLint line_list[][2] = {0, 1,//00, 3,//10, 4,//21, 2,//31, 5,//42, 3,//52, 6,//63, 7,//74, 5,//84, 7,//95, 6,//106, 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 pointsfor (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坐标可以控制三个顶点//找到前两条线的交点,横坐标为vertexif (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坐标可以控制三个顶点//找到前两条线的交点,横坐标为vertexif (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;}

效果还是可以的,如果有空的话我打算把面表和几次都写了

现在先放下暂时效果


因为没有好的数据结构,因此只能先确定点、边和面的顺序、、并且仔细计算按照我们规定的顺序,第几个出现的边会出现在我希望的顶点周围。。之后我会用比较好的数据结构改进算法

3 0
原创粉丝点击