经过前面两节的功夫,我们算是搞到了一个还算可以的模型,但我们想要把模型翻来翻去,移动一下还是不行的。并且,根据用户(老师)需求,我们要让模型能以线框,点的方式绘制。也就有了这最后一讲。
首先,我们通过鼠标左键来旋转物体。这就需要在鼠标回调函数里下功夫了
if (state == GLUT_DOWN && button == GLUT_LEFT_BUTTON)//记录旋转拖动起始点
{
flag = 0;
r_x1 = r_x2 = x;
r_y1 = r_y2 = y;
}
if (state == GLUT_UP && button == GLUT_LEFT_BUTTON)//记录旋转拖动最终点并将旋转量储存进d,e
{
d += (r_x2 - r_x1) / 3;
e -= (r_y2 - r_y1) / 3;
r_x1 = r_x2 = r_y1 = r_y2 = 0;
}
这里的d,e分别代表了绕着y和x轴旋转的分量。为什么没有Z?因为我们可以用x,y的旋转来代替绕Z的旋转,这里不具体说明了。
我们用同样的方法设置中键绑定平移操作。
if (state == GLUT_DOWN && button == GLUT_MIDDLE_BUTTON)//记录平移拖动起始点
{
flag = 1;
mov_x1 = mov_x2 = x;
mov_y1 = mov_y2 = y;
}
if (state == GLUT_UP && button == GLUT_MIDDLE_BUTTON)//记录平移最终点,并将平移量存入trans_x,trans_y
{
trans_x += mov_x2 - mov_x1;
trans_y += mov_y1 - mov_y2;
mov_x1 = mov_y1 = mov_x2 = mov_y2 = 0;
}
同时,我们需要在鼠标移动的回调函数里做更改来实现拖动。
void end(int x, int y)
{
if (!flag)
{
r_x2 = x;
r_y2 = y;
}
if (flag == 1)
{
mov_x2 = x;
mov_y2 = y;
}
}
我们增加flag来区别左键和中键的拖动。
最后写一个简单的菜单实现绘制的切换。这里不多说明,可以看源代码里的操作。同时源代码里增加了支持键盘改变视角和模型的函数。
#include
#include
#include//使用glew库使用VBO
#include
#include
#include
#include
#include
#define BUFFER_OFFSET(bytes) ((GLubyte*)NULL+bytes)
#define T 100
#pragma comment(lib, "glew32.lib")//加个glew使用VBO,啧
using namespace std;
struct Vertex
{
GLfloat x, y, z, nx, ny, nz;
}ver;
struct Index
{
GLuint a, b, c;
};
struct Index_Line
{
GLuint a, b;
};
Vertex* v_arr;//点集
Index* index_arr;//面索引
Index_Line* index_line_arr;//线索引
int v_num, index_num;
double a, b, c;//相机位置
double d, e, f;//旋转角度
GLuint VBO;//只有一个的孤独VBO
GLuint EBO[2];//索引缓冲指针
GLfloat l_position[4] = { 0,0,0,1 };
GLfloat r_x1, r_y1, r_x2, r_y2;//鼠标拖动参数
GLint tag = 2;//初始表示画多边形
GLfloat mov_x1, mov_y1, mov_x2, mov_y2;//平移变量
GLfloat trans_x, trans_y;
GLfloat T_x, T_y, T_z;
GLint flag;//0表示鼠标左键按下,1表示中键按下
void init(void)
{
T_x = T_y = T_z = 0;
char ch[50];
ifstream in("lizhenxiout-repaired.ply");
bool www = in.fail();
for (int i = 0; i < 3; i++)
in.getline(ch, 50);
in >> ch;
in >> ch;
in >> ch;
v_num = atoi(ch);
for (int i = 0; i < 7; i++)
in.getline(ch, 50);
in >> ch;
in >> ch;
in >> ch;
index_num = atoi(ch);
for (int i = 0; i < 2; i++)
in.getline(ch, 50);
in.getline(ch, 50);
//愚蠢的头部读取完毕
v_arr = new Vertex[v_num];
index_arr = new Index[index_num];
index_line_arr = new Index_Line[3 * index_num];
for (int i = 0; i < v_num; i++)
{
in >> v_arr[i].x >> v_arr[i].y >> v_arr[i].z >> v_arr[i].nx >> v_arr[i].ny >> v_arr[i].nz;
T_x += v_arr[i].x;
T_y += v_arr[i].y;
T_z += v_arr[i].z;
}
T_x /= v_num;
T_y /= v_num;
T_z /= v_num;
for (int i = 0; i < index_num; i++)
{
in >> index_arr[i].a >> index_arr[i].a >> index_arr[i].b >> index_arr[i].c;
index_line_arr[3 * i].a = index_line_arr[3 * i + 2].b = index_arr[i].a;
index_line_arr[3 * i + 1].a = index_line_arr[3 * i].b = index_arr[i].b;
index_line_arr[3 * i + 2].a = index_line_arr[3 * i + 1].b = index_arr[i].c;
}
//使用VBO加载数据
glGenBuffers(1, &VBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, v_num*sizeof(Vertex), v_arr, GL_STATIC_DRAW);
//建立EBO索引
glGenBuffers(2, EBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO[0]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, index_num*sizeof(Index), index_arr, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO[1]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, 3 * index_num*sizeof(Index_Line), index_line_arr, GL_STATIC_DRAW);
//设置顶点和法线指针
glVertexPointer(3, GL_FLOAT, 6 * sizeof(GLfloat), BUFFER_OFFSET(0));
glNormalPointer(GL_FLOAT, 6 * sizeof(GLfloat), BUFFER_OFFSET(3 * sizeof(GLfloat)));
//开启对应功能
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
glShadeModel(GL_SMOOTH);
glEnable(GL_DEPTH_TEST);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glEnable(GLUT_MULTISAMPLE);
glMatrixMode(GL_PROJECTION);//设置投影矩阵
glLoadIdentity();
gluPerspective(60, 1, 0.1, 100000);
glClearColor(0, 0, 0, 1);
a = 200;
b = 0.0;
c = 0.0;
d = e = f = 0;
trans_x = trans_y = 0;
r_x1 = r_y1 = r_x2 = r_y2 = 0;
mov_x1 = mov_y1 = mov_x2 = mov_y2 = 0;
}
void timerFunc(int value)
{
glutPostRedisplay();
glutTimerFunc(10, timerFunc, 1);
}
void display(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear Screen And Depth Buffer
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glLightfv(GL_LIGHT0, GL_POSITION, l_position);
gluLookAt(b, c, a,
T_x, T_y, T_z,
0, 1, 0);
glTranslated(trans_x + (mov_x2 - mov_x1)+T_x, trans_y + (mov_y1 - mov_y2)+T_y, T_z);
glRotatef(d + (r_x2 - r_x1) / 3, 0, 1, 0);
glRotatef(e - (r_y2 - r_y1) / 3, 1, 0, 0);
glRotatef(f, 0, 0, 1);
glTranslated(-trans_x - (mov_x2 - mov_x1)-T_x, -trans_y - (mov_y1 - mov_y2)-T_y, -T_z);
glTranslated(trans_x + (mov_x2 - mov_x1), trans_y + (mov_y1 - mov_y2), 0);
if (tag == 2)
{
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO[0]);
glDrawElements(GL_TRIANGLES, 3 * index_num, GL_UNSIGNED_INT, 0);
}
if (tag == 1)
{
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO[1]);
glDrawElements(GL_LINES, 2 * 3 * index_num, GL_UNSIGNED_INT, 0);
}
if (tag == 0)
{
glDrawArrays(GL_POINTS, 0, v_num);
}
//测试用三角形
//glBegin(GL_TRIANGLES);
//glVertex3i(-100, 0, 0);
//glVertex3i(100, 0, 0);
//glVertex3i(0, 200, 0);
//glEnd();
glutSwapBuffers();
}
void s_input(int key, int x, int y)//方向键改变相机Z
{
if (key == GLUT_KEY_DOWN)
a += 10;
if (key == GLUT_KEY_UP)
a -= 10;
}
void input(unsigned char key, int x, int y)
{
switch (key)//你还是可以通过键盘控制参数
{
case'w':c += 10; break;//相机x,y移动
case's':c -= 10; break;
case'a':b -= 10; break;
case'd':b += 10; break;
case'h':d -= 5; break;//三个旋转度设置
case'k':d += 5; break;
case'u':e -= 5; break;
case'j':e += 5; break;
case'i':f += 5; break;
case'y':f -= 5; break;
default:
break;
}
}
void start(int button, int state, int x, int y)
{
if (state == GLUT_DOWN && button == GLUT_LEFT_BUTTON)//记录旋转拖动起始点
{
flag = 0;
r_x1 = r_x2 = x;
r_y1 = r_y2 = y;
}
if (state == GLUT_DOWN && button == GLUT_MIDDLE_BUTTON)//记录旋转拖动起始点
{
flag = 1;
mov_x1 = mov_x2 = x;
mov_y1 = mov_y2 = y;
}
if (state == GLUT_UP && button == GLUT_LEFT_BUTTON)//记录旋转拖动最终点并将旋转量储存进d,e
{
d += (r_x2 - r_x1) / 3;
e -= (r_y2 - r_y1) / 3;
r_x1 = r_x2 = r_y1 = r_y2 = 0;
}
if (state == GLUT_UP && button == GLUT_MIDDLE_BUTTON)//记录平移最终点,并将平移量存入trans_x,trans_y
{
trans_x += mov_x2 - mov_x1;
trans_y += mov_y1 - mov_y2;
mov_x1 = mov_y1 = mov_x2 = mov_y2 = 0;
}
}
void end(int x, int y)
{
if (!flag)
{
r_x2 = x;
r_y2 = y;
}
if (flag == 1)
{
mov_x2 = x;
mov_y2 = y;
}
}
void menu(int value)
{
tag = value;
}
int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowSize(500, 500);
glutInitWindowPosition(100, 100);
glutCreateWindow(argv[0]);
GLenum err = glewInit();//初始化glew
if (GLEW_OK != err)
{
exit(0);
}
init();
glutDisplayFunc(display);
glutTimerFunc(10, timerFunc, 1);
glutSpecialFunc(s_input);
glutKeyboardFunc(input);
glutMouseFunc(start);
glutMotionFunc(end);
int menu_id = glutCreateMenu(menu);
glutAddMenuEntry("dot", 0);
glutAddMenuEntry("line", 1);
glutAddMenuEntry("polygon", 2);
glutAttachMenu(GLUT_RIGHT_BUTTON);
glutMainLoop();
return 0;
}