我是靠谱客的博主 高贵发卡,最近开发中收集的这篇文章主要介绍【OpenGL】绘制矩形绘制三角形选择拾取基础教程,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

上上个星期老师布置了一个大工程让我们写,感觉得到了很多提升,选择拾取这部分也是非常难的。

特此总结,并且那次去问老师题目,老师不但很有耐心,还给了我一个苹果,纪念一下。

  1. 基本情况介绍

总共代码331行,函数12个


运行效果

首先点击右键,会出现菜单


鼠标左键点击进入相应功能,画矩形时左键点两下(对角线)即可,画三角形时点三下,选择区域要在已经画了图形的情况下点(也不是不能进啦,只是没有意义),选择拾取效果如下



点击红点点那块,有四个图形重叠的部分,左边的框输出

hit = 4等等信息(上面的是之前点击写出的信息,不用管)

下面一起来看这三个功能怎么完成吧

首先看主函数

#include <stdlib.h>
#include <iostream>
#include <stdio.h>
#ifdef __APPLE__
#include <GLUT/glut.h>
#else
#include <GL/glut.h>


#endif


#ifndef __cplusplus
#define bool int
#define true 1
#define false 0
#endif
#define SIZE 101


using namespace std;


int ww,hh;//viewport
GLint numRect = 0,numTri = 0; 
int selectArray[2][SIZE];//第0行存矩形,第1行存三角形


int arrayRect[SIZE][4];
int arrayTri [SIZE][6];
int main(int argc, char** argv)
{
   glutInit(&argc, argv);
   glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB);
   glutInitWindowSize (500, 500);
   glutInitWindowPosition (0, 0);
   glutCreateWindow ("a_real_magic");//输出框的名字
   glutReshapeFunc (myreshape);//注册重绘函数
   glutDisplayFunc(display);//注册显示函数
   glutKeyboardFunc(keyboard);
 
   init();
  
	glutCreateMenu(mainMenu);           //创建主菜单,并使用回调函数mainMenu  
	glutAddMenuEntry("画个矩形", 1);       //加入菜单项  给每一个选项取一个ID一样的东西,就是后面的1 2 3
	glutAddMenuEntry("画个三角形", 2);  
	glutAddMenuEntry("选择区域", 3); 
	glutAddMenuEntry("退出", 4); 
	glutAttachMenu(GLUT_RIGHT_BUTTON); 

   glutMainLoop();
   return 0; 
}

OpenGL流水线会把这些都执行,然而什么都没有发生对不对,接着进入事件循环啦,glutMainLoop()

这时,如果我们点击鼠标右键,打开菜单,我们就进入菜单函数了

void mainMenu(int id)  //菜单函数
{  //上面注册菜单的时候不是给每个选项ID了吗
    switch(id)  
    {  
    case 1: //所以如果点击“画个矩形”就进入相应的case 1:
		glutMouseFunc (draw_PolyGon);//接着调用draw_PolyGon这个鼠标响应函数啦
		break;
        //...  
    case 2: 
		glutMouseFunc (draw_Triangle);//三角形,同理
		break;
	case 3:
		glutMouseFunc (pick);//选择拾取
		break;
	case 4:
		exit(0);//退出
        //...  
    }  
}  

顺便一提我们也注册了一个键盘响应函数

void keyboard(unsigned char key, int x, int y)//按esc退出程序的键盘响应函数
{
   switch (key) {
      case 27://为什么是27呢?因为ESC键对应的键码就是27,可以通过百度看其他按键的键盘码哦
         exit(0);
         break;
	 
   }
}

接下来进入绘制矩形的任务了

void draw_PolyGon(int button, int state, int x, int y){//自己写的鼠标响应函数,画矩形
	static bool first = true;//判断是否为鼠标第一次点击
	static int xx, yy;
	if(button == GLUT_RIGHT_BUTTON && state == GLUT_DOWN  )//按鼠标右键退出程序
		exit(0);
	if(button == GLUT_LEFT_BUTTON && state == GLUT_DOWN  )//如果左键被按下
	{
		if (first)
		{
			xx = x;
			yy = hh - y;//坐标系转换
			first = !first;//第一次点击结束后first为假,退出draw_PolyGon函数
		}
		else//如果是第二次点击
		{
			first = !first;
	//		glBegin(GL_LINE_LOOP);//画线
	//		glClear(GL_COLOR_BUFFER_BIT);

			arrayRect[numRect][0] = xx;//把坐标信息都存进数组里
			arrayRect[numRect][1] = yy;//这是第一次点击的横纵坐标
			arrayRect[numRect][2] = x;//第二次点击的横纵坐标
			arrayRect[numRect++][3] = hh - y;
		
	
			glutPostRedisplay();//标志画面需要重绘
		}
	}
}

接下来要进入难点啦,

我们为什么不直接在这个函数里把矩形画出来,而是把点存进数组呢?

因为OpenGL一旦从绘制模式变为选择模式,他就会丢失绘制模式的所有图像,我们进入选择模式之后就会一脸懵???

嗯???我们的图形呢?都不见了,而且我们也不知道自己画哪了,因为没有用数组存下来啊,所以我们要存下来,把画的任务交给其他函数,在调用glutPostRedisplay()之后,我们就会调用在主函数里注册的显示函数display,(叫什么是不要紧的,如果你在主函数里把显示回调函数写成翠花,那就在这里喊翠花来画画)

翠花长这样

void display(void){//显示回调函数
	glClear(GL_COLOR_BUFFER_BIT);
	drawObjects(GL_RENDER);
	glFlush();
}

进入display之后,display又调用drawObject了,这个drawObject就很厉害了

void drawObjects(GLenum mode)//选择模式下的求交重新绘制函数
{
	int i;
	if (mode == GL_SELECT)//如果是选择模式的话我们就进入这个,但是现在我们点了两个点,还是绘制模式呢,所以不进入这个分支
	{
		glLoadName(1);//矩形
		glPushName(0);
	}
	for(i=0; i<numRect && i<SIZE; i++){
		if(mode == GL_SELECT)
			glLoadName(i);
		if(selectArray[0][i] == 1)//true
			glColor3f(0.0, 1.0, 0.0);//selectArray后面会讲到,现在这里全是0所以进入else
		else
		{
			glColor3f(1.0, 1.0, 1.0);//矩形是白色的
		}
		glRecti(arrayRect[i][0],arrayRect[i][1],arrayRect[i][2],arrayRect[i][3]);//画出矩形
	
	}
	
	if(mode == GL_SELECT)
	{
		glPopName();
		glPopName();
		glPushName(2);//三角形的名字是2
		glPushName(0);
	}
	for(i=0; i<numTri && i<SIZE; i++){
		if(mode == GL_SELECT)
			glLoadName(i);
		if(selectArray[1][i] == 2)//true
			glColor3f(0.0, 0.0, 1.0);
		else
			glColor3f(1.0, 1.0, 1.0);
		glBegin(GL_TRIANGLES);//画出三角形
			glVertex2i(arrayTri[i][0],arrayTri[i][1]);
			glVertex2i(arrayTri[i][2],arrayTri[i][3]);
			glVertex2i(arrayTri[i][4],arrayTri[i][5]);
		glEnd();
	}
		   clearselectedArray();//清除选择数组
}
void clearselectedArray(){
	int i,j;
	for(i=0;i<2;i++)
		for(j=0;j<SIZE;j++){
			selectArray[i][j] = 0;	
		}

}

到目前为止,屏幕上就出现了一个白色矩形,然后我们再画矩形三角形,调用顺序一样

接着,我们点选择拾取,进入非常非常非常非常重要的部分了

void pick(int button, int state, int x, int y)//计数pick函数
{
   GLuint selectBuf[SIZE];
   GLint hits;
   GLint viewport[4];

   if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) 
   {   
	   glSelectBuffer (SIZE, selectBuf);//初始化selectBuf指针,进入选择模式前必做,后面的是数组指针
	   glRenderMode(GL_SELECT);//进入选择模式

	   glInitNames();//初始化名称
	   glPushName(0);//进栈
	 
	   glGetIntegerv (GL_VIEWPORT, viewport);//把左边的状态的值输出到右边
	   glMatrixMode (GL_PROJECTION);

	   glPushMatrix ();
	   glLoadIdentity ();
	/*  create 5x5 pixel picking region near cursor location	*/
	   gluPickMatrix ((GLdouble) x, (GLdouble) (viewport[3] - y), 
					  5.0, 5.0, viewport);
	   //设置拾取框的函数xy是鼠标点击到窗口上的坐标,width,height拾取框的长宽,55是选择框的大小
	   //viewport是为了得到窗口大小
	//   gluOrtho2D (-2.0, 2.0, -2.0, 2.0);//重定义标尺
	   gluOrtho2D(0.0, (GLfloat)ww, 0.0, (GLfloat)hh);
	   drawObjects(GL_SELECT);

	   glMatrixMode (GL_PROJECTION);
	   glPopMatrix ();//出栈
	   
	   hits = glRenderMode (GL_RENDER);//进入绘制模式,选择模式结束
	   processHits (hits, selectBuf);//这是自己写的一个函数用于输出
	   glutPostRedisplay();
//	   //标记当前窗口需要重新绘制

   }
} 



最后

以上就是高贵发卡为你收集整理的【OpenGL】绘制矩形绘制三角形选择拾取基础教程的全部内容,希望文章能够帮你解决【OpenGL】绘制矩形绘制三角形选择拾取基础教程所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(62)

评论列表共有 0 条评论

立即
投稿
返回
顶部