概述
上上个星期老师布置了一个大工程让我们写,感觉得到了很多提升,选择拾取这部分也是非常难的。
特此总结,并且那次去问老师题目,老师不但很有耐心,还给了我一个苹果,纪念一下。
- 基本情况介绍
总共代码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】绘制矩形绘制三角形选择拾取基础教程所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复