OpenGL基础:glut处理鼠标事件(含滚轮输入)

检测鼠标单击

要想在OpenGL中处理鼠标事件非常的方便,GLUT已经为我们的注册好了函数,只要我们提供一个方法。使用函数glutMouseFunc,就可以帮我们注册我们的函数,这样当发生鼠标事件时就会自动调用我们的方法。

函数的原型是:

void glutMouseFunc(void(*func)(int button,int state,int x,int y));  
参数:  
func:处理鼠标click事件的函数的函数名。

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

GLUT_LEFT_BUTTON
GLUT_MIDDLE_BUTTON
GLUT_RIGHT_BUTTON
// 下面两个是重构的OpenGL库函数中带的值,表示滚轮上下滚动的状态
GLUT_WHEEL_UP
GLUT_WHEEL_DOWN

第二个参数表明,函数被调用发生时,鼠标键的状态,也就是被按下,或松开,可能取值如下:

GLUT_DOWN
GLUT_UP

当函数被调用时,state的值是GLUT _DOWN。那么程序可能会假定将会有个GLUT _UP事件,甚至鼠标移动到窗口外面,也如此。然而,如果程序调用glutMouseFunc传递NULL作为参数,那么GLUT将不会改变鼠标的状态。

剩下的两个参数(x,y)提供了鼠标当前的窗口坐标(以左上角为原点)。

检测动作

GLUT提供鼠标动作检测能力。有两种GLUT处理的motion:active motion和passive motion。

Active motion是指鼠标移动并且有一个鼠标键被按下。
  Passive motion是指当鼠标移动时,并有没鼠标键按下。
  如果一个程序正在追踪鼠标,那么鼠标移动期间,每一帧将产生一个结果。

和以前一样,你必须注册将处理鼠标事件的函数(定义函数)。GLUT让我们可以指定两个不同的函数,一个追踪passive motion,另一个追踪active motion。

函数原型如下:

void glutMotionFunc(void(*func)(int x,int y));
void glutPassiveMotionFunc(void (*func)(int x,int y));
参数:
Func:处理各自类型motion的函数名。
处理motion的参数函数的参数(x,y)是鼠标在窗口的坐标。以左上角为原点。

检测鼠标进入或离开窗口

GLUT还能检测鼠标鼠标离开,进入窗口区域。一个回调函数可以被定义去处理这两个事件。GLUT里,调用这个函数的是glutEntryFunc,函数原型如下:

void glutEntryFunc(void(*func)(int state));
参数:
Func:处理这些事件的函数名。
上面函数的参数中,state有两个值表明是离开还是进入窗口:
GLUT_LEFT
GLUT_ENTERED

应用

现在想实现的功能就是使用鼠标拖动,来转动场景中的物体,当鼠标左键按下,并且上下左右滑动时,场景中的模型相应的会随之上下左右旋转,当鼠标右键按下,并且上下左右滑动时,场景中的模型相应的会随之在屏幕中进行平移。

首先,定义几个全局变量:

bool mouseLeftDown;
bool mouseRightDown;
bool mouseMiddleDown;
float mouseX, mouseY;
float cameraDistanceX;
float cameraDistanceY;
float cameraAngleX;
float cameraAngleY;
float times=1;

其中,mouseLeftDown和 mouseRightDown变量标志鼠标左右键按下与否,mouseX和mouseY变量标志鼠标滑动时,前一刻的鼠标所在位置。
  cameraDistanceX和cameraDistanceY变量根据鼠标右键按下并滑动操作来控制模型物体的平移。cameraAngleX和cameraAngleY变量根据鼠标左键按下并滑动来控制场景中物体的旋转。
  times变量表示缩放倍数,默认是原样缩放,为1倍。

void mouseCB(int button, int state, int x, int y)
{
    mouseX = x;
    mouseY = y;
    times = 1;

    if(button == GLUT_LEFT_BUTTON)
    {
        if(state == GLUT_DOWN)
        {
            mouseLeftDown = true;
        }
        else if(state == GLUT_UP)
            mouseLeftDown = false;
    }

    else if(button == GLUT_RIGHT_BUTTON)
    {
        if(state == GLUT_DOWN)
        {
            mouseRightDown = true;
        }
        else if(state == GLUT_UP)
            mouseRightDown = false;
    }

    /*
    * 鼠标滚轮控制图形缩放
    */
    else if (state == GLUT_UP && button == GLUT_WHEEL_UP)
    {
        times = 0.008f+1;
        glutPostRedisplay();
    }

    else if (state == GLUT_UP && button == GLUT_WHEEL_DOWN)
    {
        times = -0.008f+1;
        glutPostRedisplay();
    }
}  

void mouseMotionCB(int x, int y)
{
    cameraAngleX = cameraAngleY = 0;
    cameraDistanceX = cameraDistanceY = 0;

    if (mouseLeftDown)
    {
        cameraAngleY += (x - mouseX) * 0.1f;
        cameraAngleX += (y - mouseY) * 0.1f;
        mouseX = x;
        mouseY = y;
    }
    if (mouseRightDown)
    {
        cameraDistanceX = (x - mouseX) * 0.002f;
        cameraDistanceY = -(y - mouseY) * 0.002f;
        mouseY = y;
        mouseX = x;
    }

    glutPostRedisplay();
}

最后,在主函数中,调用相应的函数注册即可:

glutMouseFunc(mouseCB);
glutMotionFunc(mouseMotionCB);

在场景中物体绘制之前,这样就可以:

glScalef(times, times, times);//缩放
glTranslatef(cameraDistanceX, cameraDistanceY, 0);
glRotatef(cameraAngleX, 1, 0, 0);
glRotatef(cameraAngleY, 0, 1, 0);

备注

由于默认的OpenGL库中,不含接收鼠标滚轮输入的库函数,故在本文中的所有与滚轮控制缩放相关的功能实现,需要配置重构的OpenGL库。具体资源及使用注意我已经打包好了,下载地址是:
  下载:OpenGL库函数拓展
  完成效果的视频演示:
  视频演示
  源码参见:
  源码传送门

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,311评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,339评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,671评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,252评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,253评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,031评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,340评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,973评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,466评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,937评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,039评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,701评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,254评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,259评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,485评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,497评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,786评论 2 345

推荐阅读更多精彩内容

  • 1 前言 一直想沿着图像处理这条线建立一套完整的理论知识体系,同时积累实际应用经验。因此有了从使用AVFounda...
    RichardJieChen阅读 5,644评论 5 12
  • 开发基于 OpenGL 的应用程序,必须先了解 OpenGL 的库函数。它采用 C 语言风格,提供大量的函数来进行...
    sillen阅读 3,035评论 0 4
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,506评论 25 707
  • 快节奏是城市的标志,如果慢下来,城市就老了,人就散了。 骑车入老城区,会看到穿着浆洗到发白的衣服的老人,坐着木椅,...
    蔚离离阅读 289评论 3 1
  • 在回家的长廊上,我看见铁栏外有一只像一只小狗大小、毛色发亮的灰色老鼠与我反方向爬行,还跟我对视了。莫名地心里咯噔了...
    ugmoon阅读 341评论 0 0