做好了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;
}
效果还是可以的,如果有空的话我打算把面表和几次都写了
现在先放下暂时效果