opengl学习笔记(三)——玩弄模型(用户交互)

经过前面两节的功夫,我们算是搞到了一个还算可以的模型,但我们想要把模型翻来翻去,移动一下还是不行的。并且,根据用户(老师)需求,我们要让模型能以线框,点的方式绘制。也就有了这最后一讲。

首先,我们通过鼠标左键来旋转物体。这就需要在鼠标回调函数里下功夫了

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;
}


你可能感兴趣的:(计算机图形学)