半边数据结构与网格细分算法(附代码)

网格细分的原理其实并不难理解,它的难点主要在于如何实现。在看过无数有原理无代码的博客后,终于决定写一写我的实现方法,并附上代码供大家参考。c++写的可能比较笨拙,望见谅。

1.半边数据结构

很好理解,就是把网格的每一条边分成两个半边,半边是有方向的同一条边的两个半边方向相反。并且一条边是属于两个面,则半边完全属于一个面。

综合上述,得到半边的数据结构为一条半边的起始顶点origin,这条半边指向的下一条半边next,这条半边对应的另外半边opposite,和这条半边所在的面IncFace。


 
 
  1. typedef struct HalfEdge//半边结构
  2. {
  3.         int origin;
  4.         struct HalfEdge* next;
  5.         struct HalfEdge* opposite;
  6.         int IncFace;
  7. }HalfEdge;

 

2.网格细分算法Loop subdivision

我只写了三角形网格的细分,即实现了Loop subdivision算法。

首先,我们应该清楚这个算法是怎样细分的:

https://img-blog.csdnimg.cn/20181103145823583.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MjAxMzA2NA==,size_16,color_FFFFFF,t_70

图中上面两种情况适用于内部点和内部边产生新点的更新,下面两种情况适用于边界点和边界产生新点的更新。

由于我只细分了闭合的三维图形,所以代码只实现了第一种情况,就不讨论第二种了。

细分过程中

  • 每一条边都会产生一个新的顶点,这个顶点由该边所在的两个面中所有顶点决定,即v = 3/8*(v1 + v3) + 1/8*(v0 + v2)
  • 每一个原来的顶点都会更新自己的坐标,这个更新由所有与它相邻的原顶点决定,即http://images2015.cnblogs.com/blog/778572/201603/778572-20160307165221257-190078282.jpg ​,其中http://images2015.cnblogs.com/blog/778572/201603/778572-20160307165237241-1432841958.jpg

所以,每次细分要做的就是处理每一个旧顶点和每一条边,生成新的顶点,再将新的顶点连接成半边和面。

 

算法思路:

1.读入图形文件,分别定义数据结构保存图形的点,线,面。定义半边数据结构,将所有边转换为半边。然后开始细分。

2.更新旧顶点:第一步,遍历所有半边,找到一条以该顶点为起始顶点的半边。第二步,通过这条半边找到它的next半边,next半边的origin为v1。再找next半边的next半边 的opposite半边,进入下一个面。第三步,重复第二步直到找到的origin点vi等于v1,则已经找到所有vi,可计算出旧顶点的更新后坐标。

3.在每条旧边上生成新顶点:遍历每一条半边,通过半边和半边的opposite边的next与origin找到两个面的所有顶点,计算出新的顶点。

4.已经得到了所有新的顶点,连接它们得到新的半边和面。画出新图,细分完成。

 

大概就是这样了,一些地方不知道是否描述清楚,不清楚的请通过代码自行理解。谢谢~

附:(写于ubuntu16.04,g++编译)


 
 
  1. #include <GL/glut.h>
  2. #include <iostream>
  3. #include <stdio.h>
  4. #include <stdlib.h>
  5. #include <math.h>
  6. #include <assert.h>
  7. #include <string.h>
  8. #include<vector>
  9. using namespace std;
  10. #define PI 3.1415926536
  11. typedef struct Vertex
  12. {
  13. float x,y,z;
  14. }Vertex;
  15. typedef struct Face
  16. {
  17. int num;
  18. int order[ 3];
  19. }Face;
  20. typedef struct HalfEdge//半边结构
  21. {
  22. int origin;
  23. struct HalfEdge* next;
  24. struct HalfEdge* opposite;
  25. int IncFace;
  26. }HalfEdge;
  27. typedef struct Map
  28. {
  29. int vs,ve,e;
  30. }Map;
  31. static char *filename= "cube.off";
  32. vector<Vertex> vertex;
  33. vector<Face> face;
  34. vector<HalfEdge*> edge;
  35. int e_num;
  36. int n_node,n_face,n_edge;
  37. int width= 800;
  38. int height= 800;
  39. int readoff(const char* filename)
  40. {
  41. FILE *fp;
  42. if(!(fp=fopen(filename, "r")))
  43. {
  44. fprintf( stderr, "Open fail");
  45. return 0;
  46. }
  47. char buffer[ 1024];
  48. if(fgets(buffer, 1023,fp))
  49. {
  50. if(! strstr(buffer, "OFF"))
  51. {
  52. printf( "It's not a OFF FILE");
  53. return 0;
  54. }
  55. if(fgets(buffer, 1023,fp))
  56. {
  57. sscanf(buffer, "%d %d %d",&n_node,&n_face,&n_edge);
  58. for( int i= 0;i<n_node;i++)
  59. {
  60. Vertex ver;
  61. fgets(buffer, 1023,fp);
  62. sscanf(buffer, "%f%f%f",&ver.x,&ver.y,&ver.z);
  63. vertex.push_back(ver);
  64. }
  65. for( int i= 0;i<n_face;i++)
  66. {
  67. fgets(buffer, 1023,fp);
  68. Face f;
  69. sscanf(buffer, "%d%d%d%d",&f.num,&f.order[ 0],&f.order[ 1],&f.order[ 2]);
  70. face.push_back(f);
  71. }
  72. }
  73. }
  74. /*
  75. for(int i=0;i<n_node;i++)
  76. {
  77. cout<<vertex[i].x<<" "<<vertex[i].y<<" "<<vertex[i].z<<endl;
  78. }
  79. */
  80. }
  81. void initEdge()//生成半边存入vector
  82. {
  83. int map[n_node][n_node]={ 0};
  84. for( int i= 0;i<n_node;i++)
  85. {
  86. for( int j= 0;j<n_node;j++)
  87. {
  88. map[i][j]= -1;
  89. }
  90. }
  91. cout<< "map="<< sizeof( map[ 0])/ sizeof( int)<< endl;
  92. e_num= 0;
  93. for( int i= 0;i<n_face;i++)
  94. {
  95. HalfEdge* edge1= new HalfEdge();
  96. HalfEdge* edge2= new HalfEdge();
  97. HalfEdge* edge3= new HalfEdge();
  98. edge1->origin=face[i].order[ 0];
  99. edge2->origin=face[i].order[ 1];
  100. edge3->origin=face[i].order[ 2];
  101. edge1->next=edge2;
  102. edge2->next=edge3;
  103. edge3->next=edge1;
  104. HalfEdge* tmpe= new HalfEdge();
  105. if( map[face[i].order[ 1]][face[i].order[ 0]]!= -1)
  106. {
  107. tmpe=edge[ map[face[i].order[ 1]][face[i].order[ 0]]];
  108. edge1->opposite=tmpe;
  109. tmpe->opposite=edge1;
  110. }
  111. else
  112. {
  113. edge1->opposite= NULL;
  114. map[face[i].order[ 0]][face[i].order[ 1]]=e_num;
  115. }
  116. e_num++;
  117. if( map[face[i].order[ 2]][face[i].order[ 1]]!= -1)
  118. {
  119. tmpe=edge[ map[face[i].order[ 2]][face[i].order[ 1]]];
  120. edge2->opposite=tmpe;
  121. tmpe->opposite=edge2;
  122. }
  123. else
  124. {
  125. edge2->opposite= NULL;
  126. map[face[i].order[ 1]][face[i].order[ 2]]=e_num;
  127. }
  128. e_num++;
  129. if( map[face[i].order[ 0]][face[i].order[ 2]]!= -1)
  130. {
  131. tmpe=edge[ map[face[i].order[ 0]][face[i].order[ 2]]];
  132. edge3->opposite=tmpe;
  133. tmpe->opposite=edge3;
  134. }
  135. else
  136. {
  137. edge3->opposite= NULL;
  138. map[face[i].order[ 2]][face[i].order[ 0]]=e_num;
  139. }
  140. e_num++;
  141. edge1->IncFace=i;
  142. edge2->IncFace=i;
  143. edge3->IncFace=i;
  144. edge.push_back(edge1);
  145. edge.push_back(edge2);
  146. edge.push_back(edge3);
  147. }
  148. n_edge=edge.size();
  149. //cout<<n_edge<<endl;
  150. //for(int i=0;i<n_edge;i++)
  151. //cout<<edge[i].origin<<" "<<edge[i].next->origin<<" "<<edge[i].next->next->origin<<" "<<edge[i].IncFace<<endl;
  152. //cout<<edge[i]->origin<<" "<<edge[i]->opposite->origin<<endl;
  153. }
  154. HalfEdge* findOriginEdge(int v)//找到从该定点出发的一条半边
  155. {
  156. for( int k= 0;k<n_edge;k++)
  157. {
  158. if(edge[k]->origin==v)
  159. return edge[k];
  160. }
  161. return NULL;
  162. }
  163. void subdivide()
  164. {
  165. vector<Vertex> vertex2;
  166. vector<Face> face2;
  167. vector<HalfEdge*> edge2;
  168. HalfEdge* he= new HalfEdge();
  169. int n;
  170. float p_sumx,p_sumy,p_sumz;
  171. float px,py,pz;
  172. float beta;
  173. cout<< "细分开始"<< endl;
  174. for( int i= 0;i<n_node;i++) //旧点更新
  175. {
  176. he=findOriginEdge(i);
  177. if(he!= NULL)
  178. {
  179. n= 0;
  180. p_sumx= 0;
  181. p_sumy= 0;
  182. p_sumz= 0;
  183. HalfEdge* e= new HalfEdge();
  184. e=he->next;
  185. int p0=e->origin;
  186. while(e->next->origin!=p0)
  187. {
  188. n++;
  189. p_sumx+=vertex[e->next->origin].x;
  190. p_sumy+=vertex[e->next->origin].y;
  191. p_sumz+=vertex[e->next->origin].z;
  192. HalfEdge* te= new HalfEdge();
  193. te=e->next->opposite;
  194. e=te->next;
  195. }
  196. n++;
  197. p_sumx+=vertex[p0].x;
  198. p_sumy+=vertex[p0].y;
  199. p_sumz+=vertex[p0].z;
  200. beta= 1/( double)n*( 0.625- pow( 0.375+ 0.25* cos( 2*PI/n), 2));
  201. px=( 1-n*beta)*vertex[i].x+beta*p_sumx;
  202. py=( 1-n*beta)*vertex[i].y+beta*p_sumy;
  203. pz=( 1-n*beta)*vertex[i].z+beta*p_sumz;
  204. Vertex v;
  205. v.x=px;
  206. v.y=py;
  207. v.z=pz;
  208. vertex2.push_back(v);
  209. }
  210. }
  211. int map1[n_node][n_node]={ 0};
  212. cout<< "map1="<< sizeof(map1[ 0])/ sizeof( int)<< endl;
  213. float qx,qy,qz;
  214. for( int i= 0;i<n_edge;i++) //新点生成
  215. {
  216. if(!map1[edge[i]->origin][edge[i]->next->origin])
  217. {
  218. int p=edge[i]->origin;
  219. int pi=edge[i]->next->origin;
  220. int pi1=edge[i]->next->next->origin;
  221. int pi0=edge[i]->opposite->next->next->origin;
  222. qx= 0.375*(vertex[p].x+vertex[pi].x)+ 0.125*(vertex[pi1].x+vertex[pi0].x);
  223. qy= 0.375*(vertex[p].y+vertex[pi].y)+ 0.125*(vertex[pi1].y+vertex[pi0].y);
  224. qz= 0.375*(vertex[p].z+vertex[pi].z)+ 0.125*(vertex[pi1].z+vertex[pi0].z);
  225. Vertex v;
  226. v.x=qx;
  227. v.y=qy;
  228. v.z=qz;
  229. vertex2.push_back(v);
  230. map1[edge[i]->origin][edge[i]->next->origin]=vertex2.size() -1;
  231. map1[edge[i]->next->origin][edge[i]->origin]=vertex2.size() -1;
  232. }
  233. }
  234. /*
  235. cout<<"新点"<<endl;
  236. for(int i=0;i<vertex2.size();i++)
  237. {
  238. cout<<vertex2[i].x<<" "<<vertex2[i].y<<" "<<vertex2[i].z<<endl;
  239. }
  240. */
  241. for( int i= 0;i<n_face;i++) //新面
  242. {
  243. int a,b,c,d,e,f;
  244. a=face[i].order[ 0];
  245. b=face[i].order[ 1];
  246. c=face[i].order[ 2];
  247. d=map1[a][b];
  248. e=map1[b][c];
  249. f=map1[a][c];
  250. Face f2;
  251. f2.num= 3;
  252. f2.order[ 0]=a;
  253. f2.order[ 1]=d;
  254. f2.order[ 2]=f;
  255. face2.push_back(f2);
  256. f2.order[ 0]=d;
  257. f2.order[ 1]=b;
  258. f2.order[ 2]=e;
  259. face2.push_back(f2);
  260. f2.order[ 0]=d;
  261. f2.order[ 1]=e;
  262. f2.order[ 2]=f;
  263. face2.push_back(f2);
  264. f2.order[ 0]=f;
  265. f2.order[ 1]=e;
  266. f2.order[ 2]=c;
  267. face2.push_back(f2);
  268. }
  269. /*
  270. cout<<"新面"<<endl;
  271. for(int i=0;i<face2.size();i++)
  272. {
  273. cout<<face2[i].order[0]<<" "<<face2[i].order[1]<<" "<<face2[i].order[2]<<endl;
  274. }
  275. */
  276. n_face=face2.size();
  277. n_node=vertex2.size();
  278. cout<<n_node<< " "<<n_face<< endl;
  279. int map2[n_node][n_node]={ 0};
  280. //int * map2=new int[n_node][n_node];
  281. for( int i= 0;i<n_node;i++)
  282. {
  283. for( int j= 0;j<n_node;j++)
  284. {
  285. map2[i][j]= -1;
  286. }
  287. }
  288. cout<< "map2="<< sizeof(map2[ 0])/ sizeof( int)<< endl;
  289. e_num= 0;
  290. for( int i= 0;i<n_face;i++) //新边
  291. {
  292. HalfEdge* edge4= new HalfEdge();
  293. HalfEdge* edge5= new HalfEdge();
  294. HalfEdge* edge6= new HalfEdge();
  295. edge4->origin=face2[i].order[ 0];
  296. edge5->origin=face2[i].order[ 1];
  297. edge6->origin=face2[i].order[ 2];
  298. edge4->next=edge5;
  299. edge5->next=edge6;
  300. edge6->next=edge4;
  301. HalfEdge* tmpe= new HalfEdge();
  302. if(map2[face2[i].order[ 1]][face2[i].order[ 0]]!= -1)
  303. {
  304. tmpe=edge2[map2[face2[i].order[ 1]][face2[i].order[ 0]]];
  305. edge4->opposite=tmpe;
  306. tmpe->opposite=edge4;
  307. }
  308. else
  309. {
  310. edge4->opposite= NULL;
  311. map2[face2[i].order[ 0]][face2[i].order[ 1]]=e_num;
  312. }
  313. e_num++;
  314. if(map2[face2[i].order[ 2]][face2[i].order[ 1]]!= -1)
  315. {
  316. tmpe=edge2[map2[face2[i].order[ 2]][face2[i].order[ 1]]];
  317. edge5->opposite=tmpe;
  318. tmpe->opposite=edge5;
  319. }
  320. else
  321. {
  322. edge5->opposite= NULL;
  323. map2[face2[i].order[ 1]][face2[i].order[ 2]]=e_num;
  324. }
  325. e_num++;
  326. if(map2[face2[i].order[ 0]][face2[i].order[ 2]]!= -1)
  327. {
  328. tmpe=edge2[map2[face2[i].order[ 0]][face2[i].order[ 2]]];
  329. edge6->opposite=tmpe;
  330. tmpe->opposite=edge6;
  331. }
  332. else
  333. {
  334. edge6->opposite= NULL;
  335. map2[face2[i].order[ 2]][face2[i].order[ 0]]=e_num;
  336. }
  337. e_num++;
  338. edge4->IncFace=i;
  339. edge5->IncFace=i;
  340. edge6->IncFace=i;
  341. edge2.push_back(edge4);
  342. edge2.push_back(edge5);
  343. edge2.push_back(edge6);
  344. }
  345. n_edge=edge2.size();
  346. /*
  347. cout<<"新边"<<endl;
  348. for(int i=0;i<edge2.size();i++)
  349. {
  350. cout<<edge2[i]->origin<<" "<<edge2[i]->next->origin<<" "<<edge2[i]->IncFace<<endl;
  351. }
  352. */
  353. vertex.assign(vertex2.begin(),vertex2.end());
  354. face.assign(face2.begin(),face2.end());
  355. edge.assign(edge2.begin(),edge2.end());
  356. cout<< "完成一次细分"<< endl;
  357. cout<<n_node<< " "<<n_edge<< " "<<n_face<< endl;
  358. }
  359. void display()
  360. {
  361. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //清除颜色和深度缓存
  362. glMatrixMode(GL_MODELVIEW);
  363. glLoadIdentity(); //重置当前的模型观察矩阵
  364. glPushMatrix();
  365. glTranslatef( 0.0f, 0.0f, -5.0f);
  366. glRotatef( 30, 0.0f, 1.0f, 0.0f); //饶轴旋转
  367. glRotatef( 30, 1.0f, 0.0f, 0.0f);
  368. glColor3f( 0.5f, 0.5f, 0.5f); //灰色
  369. glBegin(GL_TRIANGLES);
  370. for( int i= 0;i<n_face;i++)
  371. {
  372. glVertex3f(vertex[face[i].order[ 0]].x,vertex[face[i].order[ 0]].y,vertex[face[i].order[ 0]].z);
  373. glVertex3f(vertex[face[i].order[ 1]].x,vertex[face[i].order[ 1]].y,vertex[face[i].order[ 1]].z);
  374. glVertex3f(vertex[face[i].order[ 2]].x,vertex[face[i].order[ 2]].y,vertex[face[i].order[ 2]].z);
  375. }
  376. glEnd();
  377. glPopMatrix();
  378. glutSwapBuffers();
  379. }
  380. void keyboard(unsigned char key, int x, int y)
  381. {
  382. switch(key)
  383. {
  384. case '1':
  385. glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
  386. break;
  387. case '2':
  388. glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
  389. break;
  390. case '3':
  391. glPolygonMode(GL_FRONT_AND_BACK, GL_POINT);
  392. break;
  393. case 'w':
  394. subdivide();
  395. break;
  396. }
  397. glutPostRedisplay();
  398. }
  399. void reshape(int w, int h) {
  400. //定义视口大小
  401. glViewport( 0, 0, (GLsizei) w, (GLsizei) h);
  402. //投影显示
  403. glMatrixMode(GL_PROJECTION);
  404. //坐标原点在屏幕中心
  405. glLoadIdentity();
  406. //操作模型视景
  407. gluPerspective( 60.0, (GLfloat) w/(GLfloat) h, 1.0, 20.0);
  408. glMatrixMode(GL_MODELVIEW);
  409. }
  410. int main(int argc,char **argv)
  411. {
  412. readoff(filename);
  413. initEdge();
  414. glutInit(&argc,argv);
  415. glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGB|GLUT_DEPTH);
  416. glutInitWindowSize(width,height);
  417. glutInitWindowPosition( 100, 100);
  418. glutCreateWindow( "loop");
  419. glutReshapeFunc(reshape);
  420. glutDisplayFunc(display);
  421. glutIdleFunc(display);
  422. glutKeyboardFunc(keyboard);
  423. glutMainLoop();
  424. return 0;
  425. }

图形文件cube.off


 
 
  1. OFF
  2. 8 12 0
  3. -0 .5 -0 .5 -0 .5
  4. 0 .5 -0 .5 -0 .5
  5. -0 .5 0 .5 -0 .5
  6. 0 .5 0 .5 -0 .5
  7. -0 .5 -0 .5 0 .5
  8. 0 .5 -0 .5 0 .5
  9. -0 .5 0 .5 0 .5
  10. 0 .5 0 .5 0 .5
  11. 3 4 5 6
  12. 3 6 5 7
  13. 3 5 1 7
  14. 3 7 1 3
  15. 3 0 3 1
  16. 3 0 2 3
  17. 3 4 6 2
  18. 3 4 2 0
  19. 3 6 7 2
  20. 3 3 2 7
  21. 3 5 4 0
  22. 3 5 0 1

 

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值