码迷,mamicode.com
首页 > 其他好文 > 详细

DOO-SABIN 细分正方体

时间:2016-05-13 00:01:52      阅读:348      评论:0      收藏:0      [点我收藏+]

标签:

做好了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;
}

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

现在先放下暂时效果

技术分享


DOO-SABIN 细分正方体

标签:

原文地址:http://blog.csdn.net/lafengxiaoyu/article/details/51344727

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!