这其实是我学习图形学以来第一次真正接触数据结构的一篇博客,除了之前用markdown写的那篇文章,那个就是入个小门。
为什么我开始接触数据机构,因为在我做第一次细分的时候就遇到了麻烦,比如DOO-SABIN细分,在每次细分的时候都需要知道这个点在哪个面上,这个点周围是哪几条边,如果按照点表边表面表,只能是按照顺序判断,这条边到了第几的位置,那么它就应该是那个点挨着的边。。这么搞显然。。
后来我得知有半边数据结构这种。。下面的一小段是一个简单的介绍
三维物体在计算机内的表示需要用具体的数据结构来实现,实体造型系统对物体的各种分析运算和操作依赖于一定的数据结构的支持。例如,在使用边界表示法( BRep)造型过程中,经常会遇到从一个点查找与该点相连的所有边,从一条边查找到该边的邻里及其邻接边,从一个面开始查找其上的外环的内环等。这些操作均需要有一个较好的数据结构来支持。造型中的数据结构本质上是对形体表示方式所需信息的存储管理,对于Brep表示就需要对定义形体的面、环、边、点及其属性进行存取、直接查找、间接查找和逆向查找等操作。
边界表示法常用的数据结构有翼边结构、对称结构等。其中翼边结构( winged edge structure)是由美国Stanford大学的B. G. Baumgar t提出的。它的基本出发点是以边为核心,每
条边上有上下两个顶点,左右两个邻面以及和顶点相连的四条边,这些边分别在两个邻面的边构成的环上。这样就可以建立起边与顶点、边与边、边与面的关系。这种数据结构可以从一条已知边出发,有规律地找到这个几何体的所有面、边和顶点。翼边结构的特点是数据结构有固定数目和长度的数据域。
在翼边结构中,与边相邻的环有两个,由于翼边结构没有明确边的正向,因此要确定当前边所在的环与面较困难,于是人们对翼边结构作了种种改进,其中芬兰赫尔辛基技术大学的Martti Mantyla 教授提出的半边结构( half - edge structure)是其中较有代表性的一种。在半边结构中,将一条边一分为二,其中一条半边属于它一个相邻面的边环,而另一条半边属于它另一个相邻面的边环(如图1所示)。每一条半边仅存储它的起点指针,这样两条半边能够表示一条边的两个端点,当搜索一个面的各端点时,只需沿着半边顺序即可。
关于半边数据结构,这里有几篇文章介绍的非常清楚。【突然发现知乎上有好多大神https://www.zhihu.com/question/25337780
还有这个外文网站的介绍更加详尽http://www.flipcode.com/archives/The_Half-Edge_Data_Structure.shtml
在做这个之前,我先把之前http://blog.csdn.net/lafengxiaoyu/article/details/51326618这篇博文里最后的一个利用邻接表的代码进行了改良,现在只有210行
代码改进还是不少的,主要这个涉及指针,顺便加上刚刚研制出来的成果,上代码
#include <windows.h>
#include <math.h>
#include <gl/GL.h>
#include<GL/glut.h>
static const GLfloat vertex_list[][3] = {
-0.5f, -0.5f, -0.5f,
0.5f, -0.5f, -0.5f,
0.5f, 0.5f, -0.5f,
-0.5f, 0.5f, -0.5f,
-0.5f, -0.5f, 0.5f,
0.5f, -0.5f, 0.5f,
0.5f, 0.5f, 0.5f,
-0.5f, 0.5f, 0.5f,
};
GLfloat colors[][3] = {
{ 1.0, 0.0, 0.0 },
{ 1.0, 1.0, 0.0 },
{ 0.0, 1.0, 0.0 },
{ 0.0, 1.0, 1.0 },
{ 1.0, 0.0, 1.0 },
{ 0.0, 0.0, 1.0 },
{ 0.0, 0.5, 0.0 },
{ 0.0, 0.5, 0.5 },
};
static const GLint index_list[][4] = {
0, 1, 2, 3,//bottem
0, 3, 7, 4,//left
2, 3, 7, 6,//front
1, 2, 6, 5,//right
0, 1, 5, 4,//back
4, 5, 6, 7//top
};
#define MAXVEX 1000 //最大顶点数
typedef int VertexType; //顶点类型应由用户定义
typedef int EdgeType; //边上的权值类型应由用户定义
typedef struct EdgeNode //边表结点
{
int adjvex; //邻接点域,存储该顶点对应的下标
struct EdgeNode *next; //链域,指向下一个邻接点
}EdgeNode;
typedef struct VertexNode //顶点表结构
{
VertexType data; //顶点域,存储顶点信息
EdgeNode *firstedge; //边表头指针
}
VertexNode, AdjList[MAXVEX];
float M_PI = 3.14159265f;
static float c = M_PI / 180.0f; //弧度和角度转换参数
static int du = 90, oldmy = -1, oldmx = -1; //du是视点绕y轴的角度,opengl里默认y轴是上方向
static float r = 3.1f, h = 0.0f; //r是视点绕y轴的半径,h是视点高度即在y轴上的坐标
float zoom = 1.0f;
void display(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(80.0f, 1.0f, 1.0f, 1000.0f);
glMatrixMode(GL_MODELVIEW);
AdjList p;
for (int i = 0; i < 8; i++)
{
p[i].data = i;
}
EdgeNode *ps;
for (int i = 0; i < 8; i++)
{
p[i].firstedge = (EdgeNode*)malloc(sizeof(EdgeNode));
ps = p[i].firstedge;
ps->next = (EdgeNode*)malloc(sizeof(EdgeNode));
ps = ps->next;
ps->next = (EdgeNode*)malloc(sizeof(EdgeNode));
ps = ps->next;
ps->next=NULL;
}
//关于0点的
p[0].firstedge->adjvex = 1;
p[0].firstedge->next->adjvex = 3;
p[0].firstedge->next->next->adjvex = 4;
//关于1点的
p[1].firstedge->adjvex = 0;
p[1].firstedge->next->adjvex = 2;
p[1].firstedge->next->next->adjvex = 5;
//关于2点的
p[2].firstedge->adjvex = 1;
p[2].firstedge->next->adjvex = 3;
p[2].firstedge->next->next->adjvex = 6;
//关于3点的
p[3].firstedge->adjvex = 0;
p[3].firstedge->next->adjvex = 2;
p[3].firstedge->next->next->adjvex = 7;
//关于4点的
p[4].firstedge->adjvex = 0;
p[4].firstedge->next->adjvex = 5;
p[4].firstedge->next->next->adjvex = 7;
//关于5点的
p[5].firstedge->adjvex = 1;
p[5].firstedge->next->adjvex = 4;
p[5].firstedge->next->next->adjvex = 6;
//关于6点的
p[6].firstedge->adjvex = 2;
p[6].firstedge->next->adjvex = 5;
p[6].firstedge->next->next->adjvex = 7;
//关于7点的
p[7].firstedge->adjvex = 3;
p[7].firstedge->next->adjvex = 4;
p[7].firstedge->next->next->adjvex = 6;
EdgeNode* pn = (EdgeNode*)malloc(sizeof(EdgeNode));
//printf("At:%.2f %.2f %.2f\n",r*cos(c*du),h,r*sin(c*du)); //这就是视点的坐标
glLoadIdentity();
gluLookAt(r*cos(c*du)*cos(c*h)*zoom, r*sin(c*h)*zoom, r*sin(c*du)*cos(c*h)*zoom, 0, 0, 0, 0, 1, 0); //从视点看远点,y轴方向(0,1,0)是上方向
for (int i = 0; i < 8; i++)
{
pn = p[i].firstedge;
do
{
glBegin(GL_LINES);
{glVertex3fv(vertex_list[p[i].data]);//其中每条边由两点组成
glVertex3fv(vertex_list[pn->adjvex]);
}
glEnd();
pn = pn->next;
} while (pn != NULL);
}
glFlush();
glutSwapBuffers();
}
void Mouse(int button, int state, int x, int y) //处理鼠标点击
{
if (state == GLUT_DOWN) //第一次鼠标按下时,记录鼠标在窗口中的初始坐标
oldmx = x, oldmy = y;
if (state == GLUT_UP && button == GLUT_WHEEL_UP)
{
zoom = zoom + 0.2;
if (zoom >= 2)zoom = 2;
//glutPostRedisplay();
}
if (state == GLUT_UP && button == GLUT_WHEEL_DOWN)
{
zoom = zoom - 0.2;
if (zoom <= 0.6) zoom = 0.6;
//glutPostRedisplay();
}
}
void onMouseMove(int x, int y) //处理鼠标拖动
{
//printf("%d\n",du);
du += x - oldmx; //鼠标在窗口x轴方向上的增量加到视点绕y轴的角度上,这样就左右转了
h += (y - oldmy); //鼠标在窗口y轴方向上的改变加到视点的y坐标上,就上下转了
if (h > 90)
{
h = 90;
}
else if (h < -90)
{
h = -90;
}
//if (h>1.0f) h = 1.0f; //视点y坐标作一些限制,不会使视点太奇怪
//else if (h<-1.0f) h = -1.0f;
oldmx = x, oldmy = y; //把此时的鼠标坐标作为旧值,为下一次计算增量做准备
}
int main(int argc, char *argv[])
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
glutInitWindowPosition(100, 100);
glutInitWindowSize(400, 400);
glutCreateWindow("OpenGL");
glutDisplayFunc(display);
glutIdleFunc(display); //设置不断调用显示函数
glutMouseFunc(Mouse);
glutMotionFunc(onMouseMove);
glutMainLoop();
return 0;
}
效果也是蛮好的,下面就对这个正方体利用半边数据结构进行重做
<pre name="code" class="cpp">
#include <windows.h>
#include <math.h>
#include <gl/GL.h>
#include<GL/glut.h>
//static const GLfloat vertex_list[][3] = {
// -0.5f, -0.5f, -0.5f,
// 0.5f, -0.5f, -0.5f,
// 0.5f, 0.5f, -0.5f,
// -0.5f, 0.5f, -0.5f,
// -0.5f, -0.5f, 0.5f,
// 0.5f, -0.5f, 0.5f,
// 0.5f, 0.5f, 0.5f,
// -0.5f, 0.5f, 0.5f,
//};
GLfloat colors[][3] = {
{ 1.0, 0.0, 0.0 },
{ 1.0, 1.0, 0.0 },
{ 0.0, 1.0, 0.0 },
{ 0.0, 1.0, 1.0 },
{ 1.0, 0.0, 1.0 },
{ 0.0, 0.0, 1.0 },
{ 0.0, 0.5, 0.0 },
{ 0.0, 0.5, 0.5 },
};
//static const GLint index_list[][4] = {
// 0, 1, 2, 3,//bottem
// 0, 3, 7, 4,//left
// 2, 3, 7, 6,//front
// 1, 2, 6, 5,//right
// 0, 1, 5, 4,//back
// 4, 5, 6, 7//top
//};
float M_PI = 3.14159265f;
static float c = M_PI / 180.0f; //弧度和角度转换参数
static int du = 90, oldmy = -1, oldmx = -1; //du是视点绕y轴的角度,opengl里默认y轴是上方向
static float r = 3.1f, h = 0.0f; //r是视点绕y轴的半径,h是视点高度即在y轴上的坐标
float zoom = 1.0f;
typedef struct HE_vert
{
float x;
float y;
float z;
struct HE_edge *edge; // one of the half-edges emantating from the vertex
}HE_vert;
typedef struct HE_edge
{
struct HE_vert *vert; // vertex at the end of the half-edge
struct HE_edge *pair; // oppositely oriented adjacent half-edge
struct HE_face *face; // face the half-edge borders
struct HE_edge *next; // next half-edge around the face
}HE_edge;
typedef struct HE_face
{
struct HE_edge *edge; // one of the half-edges bordering the face
}HE_face;
void display(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(80.0f, 1.0f, 1.0f, 1000.0f);
glMatrixMode(GL_MODELVIEW);
struct HE_vert *v[8];
for (int i = 0; i < 8; i++)
{
v[i] = (HE_vert*)malloc(sizeof(HE_vert));
}
struct HE_edge *e[6][4];
for (int i = 0; i < 6; i++)
{
for (int j = 0; j < 4;j++)
{
e[i][j] = (HE_edge*)malloc(sizeof(HE_edge));
}
}
struct HE_face *f[6];
for (int i = 0; i < 6; i++)
{
f[i] = (HE_face*)malloc(sizeof(HE_face));
}
//初始化点
v[0]->x = -0.5f; v[0]->y = -0.5f; v[0]->z = -0.5f; v[0]->edge = e[0][0];
v[1]->x = 0.5f; v[1]->y = -0.5f; v[1]->z = -0.5f; v[1]->edge = e[0][1];
v[2]->x = 0.5f; v[2]->y = 0.5f; v[2]->z = -0.5f; v[2]->edge = e[0][2];
v[3]->x = -0.5f; v[3]->y = 0.5f; v[3]->z = -0.5f; v[3]->edge = e[0][3];
v[4]->x = -0.5f; v[4]->y = -0.5f; v[4]->z = 0.5f; v[4]->edge = e[5][0];
v[5]->x = 0.5f; v[5]->y = -0.5f; v[5]->z = 0.5f; v[5]->edge = e[0][3];
v[6]->x = 0.5f; v[6]->y = 0.5f; v[6]->z = 0.5f; v[6]->edge = e[0][2];
v[7]->x = -0.5f; v[7]->y = 0.5f; v[7]->z = 0.5f; v[7]->edge = e[0][1];
//struct HE_edge
//{
// HE_vert* vert; // vertex at the end of the half-edge
// HE_edge* pair; // oppositely oriented adjacent half-edge
// HE_face* face; // face the half-edge borders
// HE_edge* next; // next half-edge around the face
//};
//初始化边
e[0][0]->vert = v[1]; e[0][0]->pair = e[4][3]; e[0][0]->face = f[0]; e[0][0]->next = e[0][1];
e[0][1]->vert = v[2]; e[0][1]->pair = e[3][3]; e[0][1]->face = f[0]; e[0][1]->next = e[0][2];
e[0][2]->vert = v[3]; e[0][2]->pair = e[2][3]; e[0][2]->face = f[0]; e[0][2]->next = e[0][3];
e[0][3]->vert = v[0]; e[0][3]->pair = e[1][3]; e[0][3]->face = f[0]; e[0][3]->next = e[0][0];
e[1][0]->vert = v[7]; e[1][0]->pair = e[2][2]; e[1][0]->face = f[1]; e[1][0]->next = e[1][1];
e[1][1]->vert = v[4]; e[1][1]->pair = e[5][0]; e[1][1]->face = f[1]; e[1][1]->next = e[1][2];
e[1][2]->vert = v[0]; e[1][2]->pair = e[4][0]; e[1][2]->face = f[1]; e[1][2]->next = e[1][3];
e[1][3]->vert = v[3]; e[1][3]->pair = e[0][3]; e[1][3]->face = f[1]; e[1][3]->next = e[1][0];
e[2][0]->vert = v[6]; e[2][0]->pair = e[3][2]; e[2][0]->face = f[2]; e[2][0]->next = e[2][1];
e[2][1]->vert = v[7]; e[2][1]->pair = e[5][1]; e[2][1]->face = f[2]; e[2][1]->next = e[2][2];
e[2][2]->vert = v[3]; e[2][2]->pair = e[1][0]; e[2][2]->face = f[2]; e[2][2]->next = e[2][3];
e[2][3]->vert = v[2]; e[2][3]->pair = e[0][2]; e[2][3]->face = f[2]; e[2][3]->next = e[2][0];
e[3][0]->vert = v[5]; e[3][0]->pair = e[4][2]; e[3][0]->face = f[3]; e[3][0]->next = e[3][1];
e[3][1]->vert = v[6]; e[3][1]->pair = e[5][2]; e[3][1]->face = f[3]; e[3][1]->next = e[3][2];
e[3][2]->vert = v[2]; e[3][2]->pair = e[2][0]; e[3][2]->face = f[3]; e[3][2]->next = e[3][3];
e[3][3]->vert = v[1]; e[3][3]->pair = e[0][1]; e[3][3]->face = f[3]; e[3][3]->next = e[3][0];
e[4][0]->vert = v[4]; e[4][0]->pair = e[1][2]; e[4][0]->face = f[4]; e[4][0]->next = e[4][1];
e[4][1]->vert = v[5]; e[4][1]->pair = e[5][3]; e[4][1]->face = f[4]; e[4][1]->next = e[4][2];
e[4][2]->vert = v[1]; e[4][2]->pair = e[3][0]; e[4][2]->face = f[4]; e[4][2]->next = e[4][3];
e[4][3]->vert = v[0]; e[4][3]->pair = e[0][0]; e[4][3]->face = f[4]; e[4][3]->next = e[4][0];
e[5][0]->vert = v[7]; e[5][0]->pair = e[1][1]; e[5][0]->face = f[5]; e[5][0]->next = e[5][1];
e[5][1]->vert = v[6]; e[5][1]->pair = e[2][1]; e[5][1]->face = f[5]; e[5][1]->next = e[5][2];
e[5][2]->vert = v[5]; e[5][2]->pair = e[3][1]; e[5][2]->face = f[5]; e[5][2]->next = e[5][3];
e[5][3]->vert = v[4]; e[5][3]->pair = e[4][1]; e[5][3]->face = f[5]; e[5][3]->next = e[5][0];
//struct HE_edge
//{
// HE_vert* vert; // vertex at the end of the half-edge
// HE_edge* pair; // oppositely oriented adjacent half-edge
// HE_face* face; // face the half-edge borders
// HE_edge* next; // next half-edge around the face
//};
f[0]->edge = e[0][0];
f[1]->edge = e[1][0];
f[2]->edge = e[2][0];
f[3]->edge = e[3][0];
f[4]->edge = e[4][0];
f[5]->edge = e[5][0];
glLoadIdentity();
gluLookAt(r*cos(c*du)*cos(c*h)*zoom, r*sin(c*h)*zoom, r*sin(c*du)*cos(c*h)*zoom, 0, 0, 0, 0, 1, 0); //从视点看远点,y轴方向(0,1,0)是上方向
struct HE_edge *en = (HE_edge*)malloc(sizeof(HE_edge));
//绘制立体图
for (int i = 0; i < 6; i++)
{
en = f[i]->edge;
glColor3f(colors[i][0], colors[i][1], colors[i][2]);
glBegin(GL_POLYGON);
do {
{
glVertex3f(en->vert->x, en->vert->y, en->vert->z);//其中每条边由两点组成
}
en = en->next;
} while (en != f[i]->edge);
glEnd();
}
for (int i = 0; i < 6; i++)
{
en = f[i]->edge;
do {
glBegin(GL_LINES);
{
glVertex3f(en->vert->x, en->vert->y, en->vert->z);//其中每条边由两点组成
glVertex3f(en->pair->vert->x, en->pair->vert->y, en->pair->vert->z);//其中每条边由两点组成
}
glEnd();
en = en->next;
} while (en != f[i]->edge);
}
glFlush();
glutSwapBuffers();
}
void Mouse(int button, int state, int x, int y) //处理鼠标点击
{
if (state == GLUT_DOWN) //第一次鼠标按下时,记录鼠标在窗口中的初始坐标
oldmx = x, oldmy = y;
if (state == GLUT_UP && button == GLUT_WHEEL_UP)
{
zoom = zoom + 0.2;
if (zoom >= 2)zoom = 2;
//glutPostRedisplay();
}
if (state == GLUT_UP && button == GLUT_WHEEL_DOWN)
{
zoom = zoom - 0.2;
if (zoom <= 0.6) zoom = 0.6;
//glutPostRedisplay();
}
}
void onMouseMove(int x, int y) //处理鼠标拖动
{
//printf("%d\n",du);
du += x - oldmx; //鼠标在窗口x轴方向上的增量加到视点绕y轴的角度上,这样就左右转了
h += (y - oldmy); //鼠标在窗口y轴方向上的改变加到视点的y坐标上,就上下转了
if (h > 90)
{
h = 90;
}
else if (h < -90)
{
h = -90;
}
//if (h>1.0f) h = 1.0f; //视点y坐标作一些限制,不会使视点太奇怪
//else if (h<-1.0f) h = -1.0f;
oldmx = x, oldmy = y; //把此时的鼠标坐标作为旧值,为下一次计算增量做准备
}
int main(int argc, char *argv[])
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
glutInitWindowPosition(100, 100);
glutInitWindowSize(400, 400);
glutCreateWindow("OpenGL");
glutDisplayFunc(display);
glutIdleFunc(display); //设置不断调用显示函数
glutMouseFunc(Mouse);
glutMotionFunc(onMouseMove);
glutMainLoop();
return 0;
}
效果已经出来了,我来解释一下
首先,定义
struct HE_vert *v[8];
for (int i = 0; i < 8; i++)
{
v[i] = (HE_vert*)malloc(sizeof(HE_vert));
}
struct HE_edge *e[6][4];
for (int i = 0; i < 6; i++)
{
for (int j = 0; j < 4;j++)
{
e[i][j] = (HE_edge*)malloc(sizeof(HE_edge));
}
}
struct HE_face *f[6];
for (int i = 0; i < 6; i++)
{
f[i] = (HE_face*)malloc(sizeof(HE_face));
}
在上面提到的那篇英文博客里写的很清楚了
//初始化点
v[0]->x = -0.5f; v[0]->y = -0.5f; v[0]->z = -0.5f; v[0]->edge = e[0][0];
v[1]->x = 0.5f; v[1]->y = -0.5f; v[1]->z = -0.5f; v[1]->edge = e[0][1];
v[2]->x = 0.5f; v[2]->y = 0.5f; v[2]->z = -0.5f; v[2]->edge = e[0][2];
v[3]->x = -0.5f; v[3]->y = 0.5f; v[3]->z = -0.5f; v[3]->edge = e[0][3];
v[4]->x = -0.5f; v[4]->y = -0.5f; v[4]->z = 0.5f; v[4]->edge = e[5][0];
v[5]->x = 0.5f; v[5]->y = -0.5f; v[5]->z = 0.5f; v[5]->edge = e[0][3];
v[6]->x = 0.5f; v[6]->y = 0.5f; v[6]->z = 0.5f; v[6]->edge = e[0][2];
v[7]->x = -0.5f; v[7]->y = 0.5f; v[7]->z = 0.5f; v[7]->edge = e[0][1];
//struct HE_edge
//{
// HE_vert* vert; // vertex at the end of the half-edge
// HE_edge* pair; // oppositely oriented adjacent half-edge
// HE_face* face; // face the half-edge borders
// HE_edge* next; // next half-edge around the face
//};
//初始化边
e[0][0]->vert = v[1]; e[0][0]->pair = e[4][3]; e[0][0]->face = f[0]; e[0][0]->next = e[0][1];
e[0][1]->vert = v[2]; e[0][1]->pair = e[3][3]; e[0][1]->face = f[0]; e[0][1]->next = e[0][2];
e[0][2]->vert = v[3]; e[0][2]->pair = e[2][3]; e[0][2]->face = f[0]; e[0][2]->next = e[0][3];
e[0][3]->vert = v[0]; e[0][3]->pair = e[1][3]; e[0][3]->face = f[0]; e[0][3]->next = e[0][0];
e[1][0]->vert = v[7]; e[1][0]->pair = e[2][2]; e[1][0]->face = f[1]; e[1][0]->next = e[1][1];
e[1][1]->vert = v[4]; e[1][1]->pair = e[5][0]; e[1][1]->face = f[1]; e[1][1]->next = e[1][2];
e[1][2]->vert = v[0]; e[1][2]->pair = e[4][0]; e[1][2]->face = f[1]; e[1][2]->next = e[1][3];
e[1][3]->vert = v[3]; e[1][3]->pair = e[0][3]; e[1][3]->face = f[1]; e[1][3]->next = e[1][0];
e[2][0]->vert = v[6]; e[2][0]->pair = e[3][2]; e[2][0]->face = f[2]; e[2][0]->next = e[2][1];
e[2][1]->vert = v[7]; e[2][1]->pair = e[5][1]; e[2][1]->face = f[2]; e[2][1]->next = e[2][2];
e[2][2]->vert = v[3]; e[2][2]->pair = e[1][0]; e[2][2]->face = f[2]; e[2][2]->next = e[2][3];
e[2][3]->vert = v[2]; e[2][3]->pair = e[0][2]; e[2][3]->face = f[2]; e[2][3]->next = e[2][0];
e[3][0]->vert = v[5]; e[3][0]->pair = e[4][2]; e[3][0]->face = f[3]; e[3][0]->next = e[3][1];
e[3][1]->vert = v[6]; e[3][1]->pair = e[5][2]; e[3][1]->face = f[3]; e[3][1]->next = e[3][2];
e[3][2]->vert = v[2]; e[3][2]->pair = e[2][0]; e[3][2]->face = f[3]; e[3][2]->next = e[3][3];
e[3][3]->vert = v[1]; e[3][3]->pair = e[0][1]; e[3][3]->face = f[3]; e[3][3]->next = e[3][0];
e[4][0]->vert = v[4]; e[4][0]->pair = e[1][2]; e[4][0]->face = f[4]; e[4][0]->next = e[4][1];
e[4][1]->vert = v[5]; e[4][1]->pair = e[5][3]; e[4][1]->face = f[4]; e[4][1]->next = e[4][2];
e[4][2]->vert = v[1]; e[4][2]->pair = e[3][0]; e[4][2]->face = f[4]; e[4][2]->next = e[4][3];
e[4][3]->vert = v[0]; e[4][3]->pair = e[0][0]; e[4][3]->face = f[4]; e[4][3]->next = e[4][0];
e[5][0]->vert = v[7]; e[5][0]->pair = e[1][1]; e[5][0]->face = f[5]; e[5][0]->next = e[5][1];
e[5][1]->vert = v[6]; e[5][1]->pair = e[2][1]; e[5][1]->face = f[5]; e[5][1]->next = e[5][2];
e[5][2]->vert = v[5]; e[5][2]->pair = e[3][1]; e[5][2]->face = f[5]; e[5][2]->next = e[5][3];
e[5][3]->vert = v[4]; e[5][3]->pair = e[4][1]; e[5][3]->face = f[5]; e[5][3]->next = e[5][0];
//struct HE_edge
//{
// HE_vert* vert; // vertex at the end of the half-edge
// HE_edge* pair; // oppositely oriented adjacent half-edge
// HE_face* face; // face the half-edge borders
// HE_edge* next; // next half-edge around the face
//};
f[0]->edge = e[0][0];
f[1]->edge = e[1][0];
f[2]->edge = e[2][0];
f[3]->edge = e[3][0];
f[4]->edge = e[4][0];
f[5]->edge = e[5][0];
初始化部分在这里,需要说明的是
v[8]表示8个点,e[ i ][ j ]表示第i个面上的第j条边
//static const GLfloat vertex_list[][3] = {
// -0.5f, -0.5f, -0.5f,
// 0.5f, -0.5f, -0.5f,
// 0.5f, 0.5f, -0.5f,
// -0.5f, 0.5f, -0.5f,
// -0.5f, -0.5f, 0.5f,
// 0.5f, -0.5f, 0.5f,
// 0.5f, 0.5f, 0.5f,
// -0.5f, 0.5f, 0.5f,
//};
//static const GLint index_list[][4] = {
// 0, 1, 2, 3,//bottem
// 0, 3, 7, 4,//left
// 2, 3, 7, 6,//front
// 1, 2, 6, 5,//right
// 0, 1, 5, 4,//back
// 4, 5, 6, 7//top
//};
点和面的顺序在此,并且我规定
地面的顺序是0->1
其他方向由此确定,并且:每个面的第一条为从顶点顺序最小的点出发的那条
这个是我画的一幅草图^^
然后就是绘图部分
struct HE_edge *en = (HE_edge*)malloc(sizeof(HE_edge));
//绘制立体图
for (int i = 0; i < 6; i++)
{
en = f[i]->edge;
do {
glBegin(GL_LINES);
{
glVertex3f(en->vert->x, en->vert->y, en->vert->z);//其中每条边由两点组成
glVertex3f(en->pair->vert->x, en->pair->vert->y, en->pair->vert->z);//其中每条边由两点组成
}
glEnd();
en = en->next;
} while (en != f[i]->edge);
}
其中对着的两条边的后点刚好确定这条边,不得不佩服涉及半边数据结构的大神
最后上效果