OpenGL实现交互

OpenGL实现交互

前言

有一说一越是学习openGL就越是能感觉到我的代码的极限 为了展示更加炫酷的效果,对图形化效果进行学习

作者 : recom

实现效果如下

1. 鼠标交互
2. 键盘交互
3. 菜单控制
4. 多页面切换GUI 待实现

实现opengl交互

实验8 OpenGL交互 鼠标 
https://www.cnblogs.com/opengl/archive/2012/10/23/2736254.html
预期实现效果,
1.菜单栏选择绘制图形样式
2.鼠标点击地点绘制模型
3.实现鼠标拖拽效果

1.鼠标交互

void glutMouseFunc(void(*func)(int button,int state,int x,int y));

参数:func:处理鼠标click事件的函数的函数名。
从上面可以看到,处理鼠标单击事件的函数,一定有4个参数。第一个参数表明哪个鼠标键被按下或松开,这个变量可以是下面的三个值中的
一个:
GLUT_LEFT_BUTTON 左键
GLUT_MIDDLE_BUTTON 中键
GLUT_RIGHT_BUTTON 右键

第二个参数表明,函数被调用发生时,鼠标的状态,也就是是被按下,或松开,可能取值如下:
GLUT_DOWN 按下
GLUT_UP   松开
当函数被调用时,state的值是GLUT_DOWN,那么程序可能会假定将会有个GLUT_UP事件,甚至鼠标移动到窗口外面,也如此。
然而,如果程序调用glutMouseFunc传递NULL作为参数,那么GLUT将不会改变鼠标的状态。
剩下的两个参数(x,y)提供了鼠标当前的窗口坐标(以左上角为原点)

实现目标: 鼠标当前位置绘制方框

1.1鼠标当前位置绘制方框

代码如下

#include <GL/glut.h>
#include <math.h>
#include <stdlib.h>
GLfloat x = 0.0;
GLfloat y = 0.0;
GLfloat size = 50.0;
GLsizei wh = 500, ww = 500;
void drawSquare(GLint x, GLint y) {
	y = wh - y;
	glBegin(GL_POLYGON);
	glVertex3f(x + size, y + size, 0);
	glVertex3f(x - size, y + size, 0);
	glVertex3f(x - size, y - size, 0);
	glVertex3f(x + size, y - size, 0);
	glEnd();
}

void mydisplay()
{
	glClear(GL_COLOR_BUFFER_BIT);
	glColor3f(1.0, 1.0, 1.0);
	drawSquare(x, y);
	glutSwapBuffers();
	glutPostRedisplay();
}
void init()
{
	glClearColor(0.0, 0.0, 0.0, 1.0);
}

void myreshape(GLint w, GLint h) {
	glViewport(0, 0, w, h);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	glOrtho(0, w, 0, h, -1.0, 1.0);
	glMatrixMode(GL_MODELVIEW);
	ww = w;
	wh = h;
}

void mymouse(GLint button, GLint state, GLint wx, GLint wy)
{
	if (button == GLUT_RIGHT_BUTTON && state == GLUT_DOWN)
		exit(0);
	if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN)
	{
		x = wx;
		y = wy;

	}
}

void main(int argc, char** argv)
{
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
	glutInitWindowSize(500, 500);
	glutInitWindowPosition(0, 0);
	glutCreateWindow("double");
	init();
	glutDisplayFunc(mydisplay);
	glutReshapeFunc(myreshape);
	glutMouseFunc(mymouse);
	glutMainLoop();
}
1.1.1实现效果

在这里插入图片描述

1.2.记录鼠标点击位置并绘图

描述效果

左键点击顶点,加入绘制点集合
右键点击一下进行绘制 两下取消绘制
点击滑轮按钮后清空绘制点集合

绘制一个三角形
出现的问题
1. opengl鼠标点击坐标和点坐标不一致
 OpenGL生成窗口,鼠标点击位置和显示位置有偏移 https://blog.csdn.net/keneyr/article/details/90111046
 我的坐标原点为屏幕中心 上 右为正方向
 鼠标坐标原点为左上角   下 右为正方向 
 进行换算后          
2. 绘制出的图形闪烁的厉害
 	开启双缓冲模式
	glutSwapBuffers();该指令在绘制函数中也使用,导致闪烁,注释后不闪烁
#include <vector>
#include<GL/glut.h>
#include<math.h>
#include<stdlib.h>
#include<iostream>
using namespace std;
GLfloat x = 0.0;
GLfloat y = 0.0;
GLfloat size = 50.0;
GLsizei wh = 500, ww = 500;
bool flag = false;
//定义用于表示像素点坐标的类Point
class Point
{
public:
	int x;
	int y;
	Point(int x, int y)
	{
		this->x = x;
		this->y = y;
	}
};
vector<Point> vectices;//待绘制的顶点集合
//绘制多边形
void plot_polygon(const vector<Point>& vertices) {
	Point startPoint = vertices[0];//定义初始点
	Point endPoint = Point(0, 0);
	//绘制直线
	glBegin(GL_LINES);
	glColor3f(1.0, 0, 0);
	for (int i = 1; i < vertices.size(); i++) {
		endPoint = vertices[i];
		glVertex2f(startPoint.x, startPoint.y);        //直线起始坐标 
		glVertex2f(endPoint.x, endPoint.y);         //直线结束坐标
		startPoint = endPoint;
	}
	endPoint = vertices[0];
	glVertex2f(startPoint.x, startPoint.y);        //直线起始坐标 
	glVertex2f(endPoint.x, endPoint.y);         //直线结束坐标
	glEnd();
	//cout << "函数内绘制成功 " << endl;
	//glFlush();
	//glutSwapBuffers();
	//glutPostRedisplay();
}
//绘制坐标轴
void display_coordinate(void) {
	//绘制x轴
	glBegin(GL_LINES);
	glVertex2f(-400, 0);        //直线起始坐标 
	glVertex2f(400, 0);         //直线结束坐标
	for (int i = 0; i < 800; i = i + 20) {
		glVertex2f(-400 + i, 0);        //直线起始坐标 
		glVertex2f(-400 + i, 0 + 10);         //直线结束坐标
	}
	//绘制箭头
	glVertex2f(400 - 20, 20);        //直线起始坐标 
	glVertex2f(400, 0);         //直线结束坐标
	glVertex2f(400 - 20, -20);        //直线起始坐标 
	glVertex2f(400, 0);         //直线结束坐标
	//绘制y轴
	glVertex2f(0, -400);        //直线起始坐标 
	glVertex2f(0, 400);         //直线结束坐标
	for (int i = 0; i < 800; i = i + 20) {
		glVertex2f(0, -400 + i);        //直线起始坐标 
		glVertex2f(10, -400 + i);         //直线结束坐标
	}
	//绘制箭头
	glVertex2f(-20, 400 - 20);        //直线起始坐标 
	glVertex2f(0, 400);         //直线结束坐标
	glVertex2f(20, 400 - 20);        //直线起始坐标 
	glVertex2f(0, 400);         //直线结束坐标
	glEnd();
	//glFlush();
	//glutSwapBuffers();
	//glutPostRedisplay();
}
void mydisplay()
{
	glClear(GL_COLOR_BUFFER_BIT);
	glColor3f(0, 0, 0);
	display_coordinate();
	if (flag==true&&vectices.size() > 2) {
		plot_polygon(vectices);
		//cout << "绘制的顶点总数为 " << vectices.size() << endl;

	}

	//glFlush与glutSwapBuffers区别 glutSwapBuffers其实就是交换缓冲区
	glutSwapBuffers();
	//glutPostRedisplay重新刷新页面绘图
	glutPostRedisplay();
}
void init(void)
{
	glClearColor(1.0, 1.0, 1.0, 0.0);
	glMatrixMode(GL_PROJECTION);
	//gluOrtho2D(0.0, windowWidth, 0.0, windowHeight);
	gluOrtho2D(-500, 500, -500, 500);
}


void mymouse(GLint button, GLint state, GLint wx, GLint wy)
{
	if (button == GLUT_RIGHT_BUTTON && state == GLUT_DOWN) {//点击鼠标右键
		if (flag == false) {
			cout << "绘制成功" << endl;
			flag = true;
		}
		else if (flag==true) {
			cout << "取消绘制" << endl;
			flag = false;
		}
	}
	if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN)//点击鼠标左键
	{
		x = (1000 - wx - 500) * -1;
		y = 1000 - wy - 500 - 40;
		cout << "绘制的顶点坐标为" << x << "  " << y << endl;
		vectices.emplace_back(Point(x, y));
	}
	if (button == GLUT_MIDDLE_BUTTON && state == GLUT_DOWN) {//点击中间进行清空
		vectices.clear();
	}
}

int main(int argc, char** argv) {
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
	glutInitWindowPosition(50, 100);
	glutInitWindowSize(1000, 1000);
	glutCreateWindow("3D Tech- GLUT Tutorial");
	init();
	glutDisplayFunc(mydisplay);
	glutMouseFunc(mymouse);
	glutMainLoop();
	return 0;
}
1.2.1效果展示

在这里插入图片描述

1.3鼠标左键拖拽绘制直线

描述

左键点击拖拽绘图,键盘z对绘制的直线进行撤销
使用vector,对鼠标点击点进行存储,并对鼠标松开点进行存储
#include <vector>
#include<GL/glut.h>
#include<math.h>
#include<stdlib.h>
#include<iostream>
using namespace std;
GLfloat x = 0.0;
GLfloat y = 0.0;
GLfloat size = 50.0;
GLsizei wh = 500, ww = 500;
bool flag = false;
//定义用于表示像素点坐标的类Point
//定义用于表示像素点坐标的类Point
class Point
{
public:
	int x;
	int y;
	Point(int x, int y)
	{
		this->x = x;
		this->y = y;
	}
};
vector<Point> vectices;//待绘制的顶点集合
//绘制坐标轴
void plot_line(const vector<Point>& vectices) {
	glBegin(GL_LINES); 
	for (int i = 0; i < vectices.size(); i = i + 2) {
		glVertex2f(vectices[i].x, vectices[i].y);
		glVertex2f(vectices[i + 1].x, vectices[i + 1].y);
	}
	glEnd();
}
void display_coordinate(void) {
	//绘制x轴
	glBegin(GL_LINES);
	glVertex2f(-400, 0);        //直线起始坐标 
	glVertex2f(400, 0);         //直线结束坐标
	for (int i = 0; i < 800; i = i + 20) {
		glVertex2f(-400 + i, 0);        //直线起始坐标 
		glVertex2f(-400 + i, 0 + 10);         //直线结束坐标
	}
	//绘制箭头
	glVertex2f(400 - 20, 20);        //直线起始坐标 
	glVertex2f(400, 0);         //直线结束坐标
	glVertex2f(400 - 20, -20);        //直线起始坐标 
	glVertex2f(400, 0);         //直线结束坐标
	//绘制y轴
	glVertex2f(0, -400);        //直线起始坐标 
	glVertex2f(0, 400);         //直线结束坐标
	for (int i = 0; i < 800; i = i + 20) {
		glVertex2f(0, -400 + i);        //直线起始坐标 
		glVertex2f(10, -400 + i);         //直线结束坐标
	}
	//绘制箭头
	glVertex2f(-20, 400 - 20);        //直线起始坐标 
	glVertex2f(0, 400);         //直线结束坐标
	glVertex2f(20, 400 - 20);        //直线起始坐标 
	glVertex2f(0, 400);         //直线结束坐标
	glEnd();
	//glFlush();
	//glutSwapBuffers();
	//glutPostRedisplay();
}
void mydisplay()
{
	glClear(GL_COLOR_BUFFER_BIT);
	glColor3f(1, 0, 0);
	display_coordinate();
	if (vectices.size() > 1&& vectices.size()%2==0) {
		plot_line(vectices);
	}
	//glFlush与glutSwapBuffers区别 glutSwapBuffers其实就是交换缓冲区
	glutSwapBuffers();
	//glutPostRedisplay重新刷新页面绘图
	glutPostRedisplay();
}
void init(void)
{
	glClearColor(1.0, 1.0, 1.0, 0.0);
	glMatrixMode(GL_PROJECTION);
	//gluOrtho2D(0.0, windowWidth, 0.0, windowHeight);
	gluOrtho2D(-500, 500, -500, 500);
}


void mymouse(GLint button, GLint state, GLint wx, GLint wy)
{
	if (button == GLUT_RIGHT_BUTTON && state == GLUT_DOWN) {//点击鼠标右键
		
	}
	if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN)//点击鼠标左键
	{
		x = (1000 - wx - 500) * -1;
		y = 1000 - wy - 500 - 40;
		cout << "绘制的顶点坐标起点为" << x << "  " << y << endl;
		vectices.emplace_back(Point(x, y));
		//glVertex2f(x, y);

	}
	if (button == GLUT_LEFT_BUTTON && state == GLUT_UP)//松开鼠标左键
	{
		
		x = (1000 - wx - 500) * -1;
		y = 1000 - wy - 500 - 40;
		cout << "绘制的顶点坐标终点为" << x << "  " << y << endl;
		vectices.emplace_back(Point(x, y));
	}
	
}
void processNormalKeys(unsigned char key, int x, int y) {
	if (key == 'z') {
		int mod = glutGetModifiers();
		if (mod == GLUT_ACTIVE_CTRL) {
			
		}
		else {
			if (vectices.size() > 1) {
				vectices.pop_back();
				vectices.pop_back();
				cout << "撤销该条线段" << endl;
			}
			else {
				cout << "撤销失败" << endl;
			}
			
			
		}
		
	}
}
int main(int argc, char** argv) {
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
	glutInitWindowPosition(50, 100);
	glutInitWindowSize(1000, 1000);
	glutCreateWindow("3D Tech- GLUT Tutorial");
	init();
	glutDisplayFunc(mydisplay);
	glutKeyboardFunc(processNormalKeys);
	glutMouseFunc(mymouse);
	glutMainLoop();
	return 0;
}
1.3.1效果展示

在这里插入图片描述

1.4 鼠标拖拽目标

#include <vector>
#include<GL/glut.h>
#include<math.h>
#include<stdlib.h>
#include<iostream>
using namespace std;
GLfloat x = 0.0;
GLfloat y = 0.0;
GLfloat size = 50.0;
GLsizei wh = 500, ww = 500;
bool flag = false;
int x_start = 0;
int y_start = 0;
int x_end = 0;
int y_end = 0;
//定义用于表示像素点坐标的类Point
class Point
{
public:
	int x;
	int y;
	Point(int x, int y)
	{
		this->x = x;
		this->y = y;
	}
};
vector<Point> vectices = {Point(100,100),Point(150,150),Point(200,100)};//待绘制的顶点集合
//绘制多边形
void plot_polygon(const vector<Point>& vertices) {
	Point startPoint = vertices[0];//定义初始点
	Point endPoint = Point(0, 0);
	//绘制直线
	glBegin(GL_LINES);
	glColor3f(1.0, 0, 0);
	for (int i = 1; i < vertices.size(); i++) {
		endPoint = vertices[i];
		glVertex2f(startPoint.x, startPoint.y);        //直线起始坐标 
		glVertex2f(endPoint.x, endPoint.y);         //直线结束坐标
		startPoint = endPoint;
	}
	endPoint = vertices[0];
	glVertex2f(startPoint.x, startPoint.y);        //直线起始坐标 
	glVertex2f(endPoint.x, endPoint.y);         //直线结束坐标
	glEnd();
	//cout << "函数内绘制成功 " << endl;
	//glFlush();
	//glutSwapBuffers();
	//glutPostRedisplay();
}
//平移
vector<Point> translation(const vector<Point>& vertices, int Tx, int Ty) {
	vector<Point> result;
	result.clear();
	for (int i = 0; i < vertices.size(); i++) {
		result.emplace_back(Point(vertices[i].x + Tx, vertices[i].y + Ty));
	}
	return result;
}
//绘制坐标轴
void display_coordinate(void) {
	//绘制x轴
	glBegin(GL_LINES);
	glVertex2f(-400, 0);        //直线起始坐标 
	glVertex2f(400, 0);         //直线结束坐标
	for (int i = 0; i < 800; i = i + 20) {
		glVertex2f(-400 + i, 0);        //直线起始坐标 
		glVertex2f(-400 + i, 0 + 10);         //直线结束坐标
	}
	//绘制箭头
	glVertex2f(400 - 20, 20);        //直线起始坐标 
	glVertex2f(400, 0);         //直线结束坐标
	glVertex2f(400 - 20, -20);        //直线起始坐标 
	glVertex2f(400, 0);         //直线结束坐标
	//绘制y轴
	glVertex2f(0, -400);        //直线起始坐标 
	glVertex2f(0, 400);         //直线结束坐标
	for (int i = 0; i < 800; i = i + 20) {
		glVertex2f(0, -400 + i);        //直线起始坐标 
		glVertex2f(10, -400 + i);         //直线结束坐标
	}
	//绘制箭头
	glVertex2f(-20, 400 - 20);        //直线起始坐标 
	glVertex2f(0, 400);         //直线结束坐标
	glVertex2f(20, 400 - 20);        //直线起始坐标 
	glVertex2f(0, 400);         //直线结束坐标
	glEnd();
	
}
void mydisplay()
{
	glClear(GL_COLOR_BUFFER_BIT);
	glColor3f(0, 0, 0);
	display_coordinate();
	plot_polygon(vectices);

	//glFlush与glutSwapBuffers区别 glutSwapBuffers其实就是交换缓冲区
	glutSwapBuffers();
	//glutPostRedisplay重新刷新页面绘图
	glutPostRedisplay();
}
void init(void)
{
	glClearColor(1.0, 1.0, 1.0, 0.0);
	glMatrixMode(GL_PROJECTION);
	//gluOrtho2D(0.0, windowWidth, 0.0, windowHeight);
	gluOrtho2D(-500, 500, -500, 500);
}


void mymouse(GLint button, GLint state, GLint wx, GLint wy)
{
	if (button == GLUT_RIGHT_BUTTON && state == GLUT_DOWN) {//点击鼠标右键
		exit(0);//结束
	}
	if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN)//点击鼠标左键
	{
		x = (1000 - wx - 500) * -1;
		y = 1000 - wy - 500 - 40;
		x_start = x;
		y_start = y;
		cout << "起始的顶点坐标为" << x << "  " << y << endl;
		
	}
	if (button == GLUT_LEFT_BUTTON && state == GLUT_UP) {//松开鼠标左键
		x = (1000 - wx - 500) * -1;
		y = 1000 - wy - 500 - 40;
		x_end = x;
		y_end = y;
		vectices=translation(vectices, x_end - x_start, y_end - y_start);
		cout << "结束的顶点坐标为" << x << "  " << y << endl;
		
		//vectices.clear();
	}
}

int main(int argc, char** argv) {
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
	glutInitWindowPosition(50, 100);
	glutInitWindowSize(1000, 1000);
	glutCreateWindow("3D Tech- GLUT Tutorial");
	init();
	glutDisplayFunc(mydisplay);
	glutMouseFunc(mymouse);
	glutMainLoop();
	return 0;
}

1.5 滚轮放缩

https://www.jianshu.com/p/c9215017d591 原始的openGL不支持滚轮,需要进行更高级的配置,所以只给出资料链接

1.6图像跟随悬浮鼠标移动

https://blog.csdn.net/wuyong2k/article/details/7839973 Glut处理鼠标事件

未找到实现的思路

或许可以通过 glutMotionFunc函数实现

1.7 绘制曲线,待完成

2.键盘交互

参考资料 https://blog.csdn.net/xie_zi/article/details/1911891 OpenGL—GLUT教程(五) GLUT键盘控制

2.1普通按键

实现 按下escape按钮进行退出

关键代码如下
void processNormalKeys(unsigned char key,int x,int y)
{
      if(key==27)
            exit(0);
}
//主函数添加
glutKeyboardFunc(processNormalKeys);

完整代码

#include <vector>
#include<GL/glut.h>
#include<math.h>
#include<stdlib.h>
#include<iostream>
using namespace std;
GLfloat x = 0.0;
GLfloat y = 0.0;
GLfloat size = 50.0;
GLsizei wh = 500, ww = 500;

//绘制坐标轴
void display_coordinate(void) {
	//绘制x轴
	glBegin(GL_LINES);
	glVertex2f(-400, 0);        //直线起始坐标 
	glVertex2f(400, 0);         //直线结束坐标
	for (int i = 0; i < 800; i = i + 20) {
		glVertex2f(-400 + i, 0);        //直线起始坐标 
		glVertex2f(-400 + i, 0 + 10);         //直线结束坐标
	}
	//绘制箭头
	glVertex2f(400 - 20, 20);        //直线起始坐标 
	glVertex2f(400, 0);         //直线结束坐标
	glVertex2f(400 - 20, -20);        //直线起始坐标 
	glVertex2f(400, 0);         //直线结束坐标
	//绘制y轴
	glVertex2f(0, -400);        //直线起始坐标 
	glVertex2f(0, 400);         //直线结束坐标
	for (int i = 0; i < 800; i = i + 20) {
		glVertex2f(0, -400 + i);        //直线起始坐标 
		glVertex2f(10, -400 + i);         //直线结束坐标
	}
	//绘制箭头
	glVertex2f(-20, 400 - 20);        //直线起始坐标 
	glVertex2f(0, 400);         //直线结束坐标
	glVertex2f(20, 400 - 20);        //直线起始坐标 
	glVertex2f(0, 400);         //直线结束坐标
	glEnd();
	
}
void mydisplay()
{
	glClear(GL_COLOR_BUFFER_BIT);
	glColor3f(0, 0, 0);
	display_coordinate();
	
	//glFlush与glutSwapBuffers区别 glutSwapBuffers其实就是交换缓冲区
	glutSwapBuffers();
	//glutPostRedisplay重新刷新页面绘图
	glutPostRedisplay();
}
void init(void)
{
	glClearColor(1.0, 1.0, 1.0, 0.0);
	glMatrixMode(GL_PROJECTION);
	//gluOrtho2D(0.0, windowWidth, 0.0, windowHeight);
	gluOrtho2D(-500, 500, -500, 500);
}
void processNormalKeys(unsigned char key, int x, int y)
{
	if (key == 27)
		exit(0);
}

int main(int argc, char** argv) {
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
	glutInitWindowPosition(50, 100);
	glutInitWindowSize(500, 500);
	glutCreateWindow("3D Tech- GLUT Tutorial");
	init();
	glutDisplayFunc(mydisplay);
	glutKeyboardFunc(processNormalKeys);
	glutMainLoop();
	return 0;
}

2.2特殊按键

实现按下F1坐标轴为红色,F2坐标轴为绿色,F3坐标轴为蓝色,F4坐标轴为黑色

void processSpecialKeys(int key, int x, int y) {
         switch(key) {
                 case GLUT_KEY_F1 :
                 	red = 1.0; green = 0.0; blue = 0.0;
                 	break;
                 case GLUT_KEY_F2 : 
                 	red = 0.0; green = 1.0; blue = 0.0;
                	break;
                 case GLUT_KEY_F3 : 
                    red = 0.0; green = 0.0; blue = 1.0; 
                    break;
                 case GLUT_KEY_F4 :
                 	red = 0.0; green = 0.0; blue = 0.0; 
                    break;
         }
}
//主函数添加 
glutSpecialFunc(processSpecialKeys);

完整代码

#include <vector>
#include<GL/glut.h>
#include<math.h>
#include<stdlib.h>
#include<iostream>
using namespace std;
GLfloat x = 0.0;
GLfloat y = 0.0;
GLfloat size = 50.0;
GLsizei wh = 500, ww = 500;
double red = 0;
double green = 0;
double blue = 0;
//绘制坐标轴
void display_coordinate(void) {
	//绘制x轴
	glBegin(GL_LINES);
	glVertex2f(-400, 0);        //直线起始坐标 
	glVertex2f(400, 0);         //直线结束坐标
	for (int i = 0; i < 800; i = i + 20) {
		glVertex2f(-400 + i, 0);        //直线起始坐标 
		glVertex2f(-400 + i, 0 + 10);         //直线结束坐标
	}
	//绘制箭头
	glVertex2f(400 - 20, 20);        //直线起始坐标 
	glVertex2f(400, 0);         //直线结束坐标
	glVertex2f(400 - 20, -20);        //直线起始坐标 
	glVertex2f(400, 0);         //直线结束坐标
	//绘制y轴
	glVertex2f(0, -400);        //直线起始坐标 
	glVertex2f(0, 400);         //直线结束坐标
	for (int i = 0; i < 800; i = i + 20) {
		glVertex2f(0, -400 + i);        //直线起始坐标 
		glVertex2f(10, -400 + i);         //直线结束坐标
	}
	//绘制箭头
	glVertex2f(-20, 400 - 20);        //直线起始坐标 
	glVertex2f(0, 400);         //直线结束坐标
	glVertex2f(20, 400 - 20);        //直线起始坐标 
	glVertex2f(0, 400);         //直线结束坐标
	glEnd();

}
void mydisplay()
{
	glClear(GL_COLOR_BUFFER_BIT);
	glColor3f(red, green, blue);
	display_coordinate();

	//glFlush与glutSwapBuffers区别 glutSwapBuffers其实就是交换缓冲区
	glutSwapBuffers();
	//glutPostRedisplay重新刷新页面绘图
	glutPostRedisplay();
}
void init(void)
{
	glClearColor(1.0, 1.0, 1.0, 0.0);
	glMatrixMode(GL_PROJECTION);
	//gluOrtho2D(0.0, windowWidth, 0.0, windowHeight);
	gluOrtho2D(-500, 500, -500, 500);
}
void processSpecialKeys(int key, int x, int y) {
	switch (key) {
	case GLUT_KEY_F1:
		red = 1.0; green = 0.0; blue = 0.0;
		break;
	case GLUT_KEY_F2:
		red = 0.0; green = 1.0; blue = 0.0;
		break;
	case GLUT_KEY_F3:
		red = 0.0; green = 0.0; blue = 1.0;
		break;
	case GLUT_KEY_F4:
		red = 0.0; green = 0.0; blue = 0.0;
		break;
	}
}

int main(int argc, char** argv) {
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
	glutInitWindowPosition(50, 100);
	glutInitWindowSize(500, 500);
	glutCreateWindow("3D Tech- GLUT Tutorial");
	init();
	glutDisplayFunc(mydisplay);
	glutSpecialFunc(processSpecialKeys);
	glutMainLoop();
	return 0;
}

2.3组合按键

怎样知道是否按下组合键

一些时候我们想知道要是一个组合键( modifier key)也就是CTRL,ALT或者SHIFT被按下该如何处理。
GLUT提供了一个函数来检测时候有组合键被按下。这个函数仅仅只能在处理按键消息或者鼠标消息函数里被调用。函数原型如下:
int glutGetModifiers(void);
这个函数的返回值是三个 glut.h里预定义的常量里的一个,或它们的或组合。这三个常量是:
1: GLUT_ACTIVE_SHIFT: 返回它,当按下SHIFT键或以按下CAPS LOCK,注意两者同时按下时,不会返回这个值。
2: GLUT_ACTIVE_CTRL: 返回它,当按下CTRL键。
3: GLUT_ACTIVE_ATL:返回它,当按下ATL键。
2.3.1示例 1

处理组合键,按下 r 键时green变量被设置为1.0,red设置为0,当按下ATL+r时red被设置为1.0,green为0.0

void processNormalKeys(unsigned char key, int x, int y) {
         if (key == 27) 
                 exit(0);
         else if (key=='r') {
                 int mod = glutGetModifiers();
                 if (mod == GLUT_ACTIVE_ALT)
                          red = 0.0;
                 else
                          red = 1.0;
         }
}
//主函数添加检测普通按键的就可以了 
glutKeyboardFunc(processNormalKeys);

完整代码

#include <vector>
#include<GL/glut.h>
#include<math.h>
#include<stdlib.h>
#include<iostream>
using namespace std;
GLfloat x = 0.0;
GLfloat y = 0.0;
GLfloat size = 50.0;
GLsizei wh = 500, ww = 500;
double red = 0;
double green = 0;
double blue = 0;
//绘制坐标轴
void display_coordinate(void) {
	//绘制x轴
	glBegin(GL_LINES);
	glVertex2f(-400, 0);        //直线起始坐标 
	glVertex2f(400, 0);         //直线结束坐标
	for (int i = 0; i < 800; i = i + 20) {
		glVertex2f(-400 + i, 0);        //直线起始坐标 
		glVertex2f(-400 + i, 0 + 10);         //直线结束坐标
	}
	//绘制箭头
	glVertex2f(400 - 20, 20);        //直线起始坐标 
	glVertex2f(400, 0);         //直线结束坐标
	glVertex2f(400 - 20, -20);        //直线起始坐标 
	glVertex2f(400, 0);         //直线结束坐标
	//绘制y轴
	glVertex2f(0, -400);        //直线起始坐标 
	glVertex2f(0, 400);         //直线结束坐标
	for (int i = 0; i < 800; i = i + 20) {
		glVertex2f(0, -400 + i);        //直线起始坐标 
		glVertex2f(10, -400 + i);         //直线结束坐标
	}
	//绘制箭头
	glVertex2f(-20, 400 - 20);        //直线起始坐标 
	glVertex2f(0, 400);         //直线结束坐标
	glVertex2f(20, 400 - 20);        //直线起始坐标 
	glVertex2f(0, 400);         //直线结束坐标
	glEnd();

}
void mydisplay()
{
	glClear(GL_COLOR_BUFFER_BIT);
	glColor3f(red, green, blue);
	display_coordinate();

	//glFlush与glutSwapBuffers区别 glutSwapBuffers其实就是交换缓冲区
	glutSwapBuffers();
	//glutPostRedisplay重新刷新页面绘图
	glutPostRedisplay();
}
void init(void)
{
	glClearColor(1.0, 1.0, 1.0, 0.0);
	glMatrixMode(GL_PROJECTION);
	//gluOrtho2D(0.0, windowWidth, 0.0, windowHeight);
	gluOrtho2D(-500, 500, -500, 500);
}
void processNormalKeys(unsigned char key, int x, int y) {
	if (key == 27)
		exit(0);
	else if (key == 'r') {
		int mod = glutGetModifiers();
		if (mod == GLUT_ACTIVE_ALT) {
			green = 1.0;
			red = 0;
		}
		else {
			red = 1.0;
			green = 0;
		}
			
	}
}

int main(int argc, char** argv) {
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
	glutInitWindowPosition(50, 100);
	glutInitWindowSize(500, 500);
	glutCreateWindow("3D Tech- GLUT Tutorial");
	init();
	glutDisplayFunc(mydisplay);
	glutKeyboardFunc(processNormalKeys);
	glutMainLoop();
	return 0;
}
2.3.2示例 2

CTRL+ALT+F1时颜色改变为红色,F1时颜色改变为绿色,F2颜色变为绿色,F3颜色变为蓝色

void processSpecialKeys(int key, int x, int y) {
         int mod;
         switch(key) {
                 case GLUT_KEY_F1 : 
                    mod = glutGetModifiers();
                    if (mod == (GLUT_ACTIVE_CTRL|GLUT_ACTIVE_ALT)) {
                          red = 1.0; green = 0.0; blue = 0.0;
                    }else
                    break;
                 case GLUT_KEY_F2 : 
                    red = 0.0; 
                    green = 1.0; 
                    blue = 0.0; break;
                 case GLUT_KEY_F3 : 
                    red = 0.0; 
                    green = 0.0; 
                    blue = 1.0; break;
         }
}
//主函数添加 
glutSpecialFunc(processSpecialKeys);
#include <vector>
#include<GL/glut.h>
#include<math.h>
#include<stdlib.h>
#include<iostream>
using namespace std;
GLfloat x = 0.0;
GLfloat y = 0.0;
GLfloat size = 50.0;
GLsizei wh = 500, ww = 500;
double red = 0;
double green = 0;
double blue = 0;
//绘制坐标轴
void display_coordinate(void) {
	//绘制x轴
	glBegin(GL_LINES);
	glVertex2f(-400, 0);        //直线起始坐标 
	glVertex2f(400, 0);         //直线结束坐标
	for (int i = 0; i < 800; i = i + 20) {
		glVertex2f(-400 + i, 0);        //直线起始坐标 
		glVertex2f(-400 + i, 0 + 10);         //直线结束坐标
	}
	//绘制箭头
	glVertex2f(400 - 20, 20);        //直线起始坐标 
	glVertex2f(400, 0);         //直线结束坐标
	glVertex2f(400 - 20, -20);        //直线起始坐标 
	glVertex2f(400, 0);         //直线结束坐标
	//绘制y轴
	glVertex2f(0, -400);        //直线起始坐标 
	glVertex2f(0, 400);         //直线结束坐标
	for (int i = 0; i < 800; i = i + 20) {
		glVertex2f(0, -400 + i);        //直线起始坐标 
		glVertex2f(10, -400 + i);         //直线结束坐标
	}
	//绘制箭头
	glVertex2f(-20, 400 - 20);        //直线起始坐标 
	glVertex2f(0, 400);         //直线结束坐标
	glVertex2f(20, 400 - 20);        //直线起始坐标 
	glVertex2f(0, 400);         //直线结束坐标
	glEnd();

}
void mydisplay()
{
	glClear(GL_COLOR_BUFFER_BIT);
	glColor3f(red, green, blue);
	display_coordinate();

	//glFlush与glutSwapBuffers区别 glutSwapBuffers其实就是交换缓冲区
	glutSwapBuffers();
	//glutPostRedisplay重新刷新页面绘图
	glutPostRedisplay();
}
void init(void)
{
	glClearColor(1.0, 1.0, 1.0, 0.0);
	glMatrixMode(GL_PROJECTION);
	//gluOrtho2D(0.0, windowWidth, 0.0, windowHeight);
	gluOrtho2D(-500, 500, -500, 500);
}
void processSpecialKeys(int key, int x, int y) {
	int mod;
	switch (key) {
	case GLUT_KEY_F1:
		mod = glutGetModifiers();
		if (mod == (GLUT_ACTIVE_CTRL | GLUT_ACTIVE_ALT)) {
			red = 1.0; green = 0.0; blue = 0.0;
		}
		else {
			red = 0.0; green = 1.0; blue = 0.0;
		}
			break;
	case GLUT_KEY_F2:
		red = 0.0;
		green = 1.0;
		blue = 0.0; break;
	case GLUT_KEY_F3:
		red = 0.0;
		green = 0.0;
		blue = 1.0; break;
	}
}

int main(int argc, char** argv) {
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
	glutInitWindowPosition(50, 100);
	glutInitWindowSize(500, 500);
	glutCreateWindow("3D Tech- GLUT Tutorial");
	init();
	glutDisplayFunc(mydisplay);
	glutSpecialFunc(processSpecialKeys);
	glutMainLoop();
	return 0;
}
2.3.2效果展示

在这里插入图片描述

3.菜单控制

参考资料 https://blog.csdn.net/xie_zi/article/details/1963383 OpenGL—GLUT教程(十) GLUT菜单

弹出式菜单(像点鼠标右键出来的菜单那样的)也是 GLUT的一部分,虽然它不能实现我们经常看到的windows系统弹出式菜单的所有的功能,但是它也有很大的作用。给一个程序增加菜单提供了一个比键盘更简单的方法来和程序交互,选择不同选项,而不用去记那些按键。

我们首先要做的是创建菜单,创建菜单函数 glutCreateMenu的原型如下:

int glutCreateMenu( void (*func)(int value));

参数:
 func:为新建的菜单处理菜单事件的函数名。
这个函数的返回值是菜单的标识符( menu identifier)。
我们的程序中,我们可以相加多少菜单就加多少菜单。对每个菜单我们要指定一个回调函数,而且我们可以指定相同的函数。
下面为菜单增加一些条目(出来个空菜单也没什么用)。

使用的函数是 glutAddMenuEntry:

void glutAddMenuEntry( char *name,int value);
参数:
 name:菜单名称的字符串。
 value:当你选择菜单里的一项后,这个值就返回给上面的 glutCreateMenu里调用的函数。
这个函数根据函数名来看,就是给菜单里添加条目的,可以一直添加(这里有个顺序,自己实验下就明白了的)。

好了现在有了一个弹出式菜单。但还有最后一件事要做,就是把菜单和一个鼠标键连接起来( attach)。因为我们必须指定菜单怎么出现,使用GLUT你可以在按下一个鼠标按键后让菜单显示,函数是glutAttachMenu:

void glutAttachMenu( int button);

参数:
 button: 一个整数,指定菜单和哪个鼠标键关联起来。
botton 可以取下面的值 ;
 GLUT_LEFT_BUTTON
 GLUT_MIDDLE_BUTTON
 GLUT_RIGHT_BUTTON

3.1通过菜单栏选择坐标轴的颜色

描述

1.通过鼠标右键展开菜单
2.通过鼠标左键选择需要修改的颜色
#define RED 1
#define GREEN 2
#define BLUE 3
#define WHITE 4
void createGLUTMenus() {
 
         int menu;
 
         // 创建菜单并告诉GLUT,processMenuEvents处理菜单事件。
         menu = glutCreateMenu(processMenuEvents);
       		
         //给菜单增加条目
         glutAddMenuEntry("Red",RED);
         glutAddMenuEntry("Blue",BLUE);
         glutAddMenuEntry("Green",GREEN);
         glutAddMenuEntry("White",WHITE);
       
         // 把菜单和鼠标右键关联起来。
         glutAttachMenu(GLUT_RIGHT_BUTTON);
}
//注意 RED,BLUE,GREEN,和WHITE必须定义为整数,再就是你必须为每个选单(菜单里的条目)定义不同的value
//下面我们写处理菜单事件的函数。我们将使用我们的菜单来设置三角形的颜色。函数如下:
void processMenuEvents(int option) {
        //option,就是传递过来的value的值。
         switch (option) {
                 case RED : 
                          red = 1.0; 
                          green = 0.0; 
                          blue = 0.0; break;
                 case GREEN : 
                          red = 0.0; 
                          green = 1.0; 
                          blue = 0.0; break;
                 case BLUE : 
                          red = 0.0; 
                          green = 0.0; 
                          blue = 1.0; break;
                 case WHITE : 
                          red = 1.0; 
                          green = 1.0; 
                          blue = 1.0; break;
         }
}
//主函数添加
//调用我们的函数来创建菜单
createGLUTMenus();

完整代码

#include <vector>
#include<GL/glut.h>
#include<math.h>
#include<stdlib.h>
#include<iostream>
using namespace std;
GLfloat x = 0.0;
GLfloat y = 0.0;
GLfloat size = 50.0;
GLsizei wh = 500, ww = 500;

#define RED 1
#define GREEN 2
#define BLUE 3
#define WHITE 4

double red = 0;
double green = 0;
double blue = 0;
//绘制坐标轴
void display_coordinate(void) {
	//绘制x轴
	glBegin(GL_LINES);
	glVertex2f(-400, 0);        //直线起始坐标 
	glVertex2f(400, 0);         //直线结束坐标
	for (int i = 0; i < 800; i = i + 20) {
		glVertex2f(-400 + i, 0);        //直线起始坐标 
		glVertex2f(-400 + i, 0 + 10);         //直线结束坐标
	}
	//绘制箭头
	glVertex2f(400 - 20, 20);        //直线起始坐标 
	glVertex2f(400, 0);         //直线结束坐标
	glVertex2f(400 - 20, -20);        //直线起始坐标 
	glVertex2f(400, 0);         //直线结束坐标
	//绘制y轴
	glVertex2f(0, -400);        //直线起始坐标 
	glVertex2f(0, 400);         //直线结束坐标
	for (int i = 0; i < 800; i = i + 20) {
		glVertex2f(0, -400 + i);        //直线起始坐标 
		glVertex2f(10, -400 + i);         //直线结束坐标
	}
	//绘制箭头
	glVertex2f(-20, 400 - 20);        //直线起始坐标 
	glVertex2f(0, 400);         //直线结束坐标
	glVertex2f(20, 400 - 20);        //直线起始坐标 
	glVertex2f(0, 400);         //直线结束坐标
	glEnd();

}
void mydisplay()
{
	glClear(GL_COLOR_BUFFER_BIT);
	glColor3f(red, green, blue);
	display_coordinate();

	//glFlush与glutSwapBuffers区别 glutSwapBuffers其实就是交换缓冲区
	glutSwapBuffers();
	//glutPostRedisplay重新刷新页面绘图
	glutPostRedisplay();
}
void init(void)
{
	glClearColor(1.0, 1.0, 1.0, 0.5);
	glMatrixMode(GL_PROJECTION);
	//gluOrtho2D(0.0, windowWidth, 0.0, windowHeight);
	gluOrtho2D(-500, 500, -500, 500);
}
//下面我们写处理菜单事件的函数。我们将使用我们的菜单来设置三角形的颜色。函数如下:
void processMenuEvents(int option) {
	//option,就是传递过来的value的值。
	switch (option) {
	case RED:
		red = 1.0;
		green = 0.0;
		blue = 0.0; break;
	case GREEN:
		red = 0.0;
		green = 1.0;
		blue = 0.0; break;
	case BLUE:
		red = 0.0;
		green = 0.0;
		blue = 1.0; break;
	case WHITE:
		red = 1.0;
		green = 1.0;
		blue = 1.0; break;
	}
}
void createGLUTMenus() {

	int menu;

	// 创建菜单并告诉GLUT,processMenuEvents处理菜单事件。
	menu = glutCreateMenu(processMenuEvents);

	//给菜单增加条目
	glutAddMenuEntry("Red", RED);
	glutAddMenuEntry("Blue", BLUE);
	glutAddMenuEntry("Green", GREEN);
	glutAddMenuEntry("White", WHITE);

	// 把菜单和鼠标右键关联起来。
	glutAttachMenu(GLUT_RIGHT_BUTTON);
}
//注意 RED,BLUE,GREEN,和WHITE必须定义为整数,再就是你必须为每个选单(菜单里的条目)定义不同的value

int main(int argc, char** argv) {
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
	glutInitWindowPosition(50, 100);
	glutInitWindowSize(500, 500);
	glutCreateWindow("3D Tech- GLUT Tutorial");
	init();
	glutDisplayFunc(mydisplay);
	createGLUTMenus();
	glutMainLoop();
	return 0;
}
3.1.1展示效果

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值