您好,欢迎访问三七文档
当前位置:首页 > 商业/管理/HR > 其它文档 > 高级计算机图形学_输入与交互_中科大
高级计算机图形学中国科学技术大学计算机学院黄章进zhuang@ustc.edu.cn第三章输入与交互第三章之第一节简介基本内容输入设备•物理设备•逻辑设备•输入模式GLUT事件驱动编程•鼠标事件•键盘事件•窗口事件Sketchpad项目IvanSutherland(MIT1963年)建立了刻画交互式计算机图形学的基本框架:•用户在显示器上看到一个对象(的图像)•用户利用输入设备(光笔、鼠标、跟踪球等)点选该对象•对象发生了改变(移动、旋转、变形等)•重复上述过程图形输入设备输入设备可以用下述两种属性中的一种进行描述•物理属性•鼠标键盘跟踪球•逻辑属性•设备通过API返回给程序的内容是什么?•位置•对象标识符(一个整数值)模式•如何以及何时获取输入?•请求(主动)或者事件(被动)物理输入设备指向设备:允许用户在屏幕上指定点的位置,有一个或多个按钮用来向计算机发送信号或中断请求键盘设备:几乎总是指键盘,也可泛指任何能向计算机传送字符编码的设备(如,软键盘)指向设备–绝对定位计算机阈值探测器光电探测器光笔数据板•绝对定位设备:直接向操作系统返回屏幕位置•数据板•光笔指向设备–相对定位鼠标跟踪球游戏操纵杆三维空间球相对定位设备鼠标、跟踪球以及游戏操纵杆等设备向操作系统返回两个正交的速度分量值•当鼠标移动时,对两个速度分量进行积分得到x和y方向上的偏移值,加到初始位置上转化为屏幕上某点的位置坐标•利用球的位置改变来确定位置,并没有利用球的绝对位置逻辑设备考虑C与C++代码:•C++:cinx;•C:scanf(”%d”,&x);输入设备是什么?•代码中并没有指明•可以是键盘、文件、或者其它程序的输出上述代码要求的就是逻辑输入•不管物理设备是什么,程序得到一个数(int)作为输入图形逻辑设备相对于非图形程序中的输入通常只是数字、字符或者字节而言,图形输入的形式更多在GKS和PHIGS这两个老的API中,定义了六种类型的逻辑输入:•定位(Locator):返回一个位置•拾取(Pick):返回对象的标识ID•键盘(Keyboard):返回字符串•笔划(Stroke):返回一组位置数据•定值(Valuator):返回模拟量输入(浮点数)•选择(Choice):返回n项中的一项客户-服务器(C-S)结构在XWindow系统中引入了适用于工作站网络的客户-服务器模型(C-S模型)•客户(Client):OpenGL程序•图形服务器(GraphicsServer):具有指向设备、键盘和位图(即光栅)显示设备打印服务器图形服务器工作站工作站计算服务器文件服务器图形服务器输入模式在输入设备中具有一个触发器(trigger),它可以向操作系统发送一个信息•鼠标上的按钮•按下/释放键盘上的键当触发后,输入设备向系统返回相应的测量值(measure)•鼠标返回位置信息•键盘返回ASCII码两种模式:请求模式和事件模式请求模式(RequestMode)只有当用户触发了设备后,输入才提供给程序键盘输入为典型例子•在按回车键(触发器)之前,可以删除(回退)、编辑、修改输入的信息用户必须指明哪个输入设备提供输入•适合程序引导用户的情形,而不适合用户控制程序执行过程触发测量值请求应用程序测量过程触发过程事件模式(EventMode)绝大部分系统具有多个输入设备,每个设备都可能被用户在任意时间触发每个触发生成一个事件,事件的测量值放到事件队列中,用户程序检查该队列,根据事件的类型采用相应的操作(回调函数)触发触发过程测量处理测量值应用程序事件队列等待事件事件类型窗口:改变尺寸、重新显示、缩成图标鼠标:点击一个或多个按钮,移动键盘:按下或释放某个键空闲:“没有事件”•可以定义如果队列中没有其它事件就可以进行的某种操作回调回调是事件驱动输入方式的程序界面为图形系统可以识别的每种类型事件定义一个回调函数当相应的事件出现时,就会自动执行用户指定的函数GLUT示例•glutMouseFunc(mouse);鼠标回调函数GLUT中的回调函数GLUT识别在各种窗口系统(Windows,X,Macintosh)中都有的一组事件•glutDisplayFunc•glutMouseFunc•glutReshapeFunc•glutKeyboardFunc•glutIdleFunc•glutMotionFunc•glutPassiveMotionFuncGLUT中的事件循环记住:在任何利用GLUT的程序中,main()的最后一行实质语句必须是glutMainLoop();这条语句使得程序进入一个无穷的事件循环每经过事件循环一次,GLUT进行下述操作•查看事件队列中的事件•对于在队列中的每个事件,如果定义了相应的回调函数,GLUT就执行这个回调函数•如果对该事件没有定义回调函数,那么就忽略该事件显示回调函数只要GLUT确定需要刷新窗口,那么就会执行显示回调函数,例如•当第一次打开窗口的时候•当改变了窗口形状的时候•当重新露出了窗口的时候•当用户程序决定需要改变显示内容的时候在main()中,•glutDisplayFunc(display)注册要执行的显示回调函数display•每个GLUT程序都必须有一个显示回调函数,必要时可以设置为空函数标识重新显示许多事件都会导致调用显示回调函数•这会导致遍历一次事件循环的过程中多次执行显示回调函数可以用下列方法避免这个问题glutPostRedisplay();这条语句设置一个标志当事件循环结束时,GLUT会检查是否设置了上述标志如果设置了标志,那么就会执行显示回调函数全局变量的应用所有GLUT回调函数的调用形式是固定的•voiddisplay();•voidmouse(intbutton,intstate,intx,inty);为了向回调函数传递信息,必须应用全局变量floatt;//全局变量voiddisplay(){//根据t绘制图形}鼠标回调函数glutMouseFunc(mouse)voidmouse(intbutton,intstate,intx,inty)•其中button的值可能是GLUT_LEFT_BUTTON,GLUT_MIDDLE_BUTTON,GLUT_RIGHT_BUTTON表示哪个按钮导致了事件发生•state表示相应按钮的状态:GL_UP,GL_DOWN•x,y表示在窗口中的位置定位在屏幕上的位置通常是以像素为单位的,原点在左上角•因为显示器自顶向下刷新显示内容在OpenGL中使用的世界坐标系,其原点在左下角在这个坐标系中的y坐标需要从窗口高度中减去回调函数返回的y值:y:=h-ywh(0,0)(x,y)yh-y获取窗口尺寸为了完成y坐标的转换,需要知道窗口的高度h•在程序执行过程中高度可能发生改变•需要利用一个全局变量跟踪其变化•新高度值返回给形状改变回调函数(见后)•也可以用查询函数glGetIntegerv和glGetFloatv获取,因为高度是状态的一部分鼠标结束程序在以前的程序中没有办法通过OpenGL结束当前程序可以利用简单的鼠标回调函数做到这一点voidmouse(intbtn,intstate,intx,inty){if(btn==GLUT_RIGHT_BUTTON&&state==GLUT_DOWN)exit(0);}鼠标位置的应用在要构造的例子中,每单击一次鼠标左按钮,就会在当前鼠标位置处画一个小方框在这个例子中并没有用到显示回调函数,但是由于GLUT要求必须有一个显示回调函数,因此要定义一个空函数display(){}在指针处画方框voidmouse(intbtn,intstate,intx,inty){if(btn==GLUT_RIGHT_BUTTON&&state==GLUT_DOWN)exit(0);if(btn==GLUT_LEFT_BUTTON&&state==GLUT_DOWN)drawSquare(x,y);}voiddrawSquare(GLintx,GLinty){y=h-y;//转化y坐标glColor3ub((char)rand()%256,(char)rand()%256,(char)rand()%256);//随机颜色glBegin(GL_POLYGON);glVertex2f(x-size,y-size);glVertex2f(x+size,y-size);glVertex2f(x+size,y+size);glVertex2f(x-size,y+size);glEnd();}鼠标移动回调函数通过利用移动回调函数可以在不释放鼠标按钮的情况下,连续画一系列方框(square.c)•glutMotionFunc(drawSquare)应用被动移动回调函数,可以不用按鼠标按钮就可以连续画方框•glutPassiveMotionFunc(drawSquare)voidglutMotionFunc(void(*f)(intx,inty))voidglutPassiveMotionFunc(void(*f)(intx,inty))键盘的使用glutKeyboardFunc(keyboard)voidkeyboard(unsignedcharkey,intx,inty)•返回键盘上被按下键的ASCII码和鼠标位置•注意在GLUT中并不把释放按键做为一个事件voidkeyboard(unsignedcharkey,intx,inty){//按下Q、q或ESC键时,终止程序if(key==‘Q’||key==‘q’||key==‘\27’)exit(0);}特殊按键GLUT在glut.h中定义了特殊按键:•功能键1:GLUT_KEY_F1•向上方向键:GLUT_KEY_UPvoidglutSpecialFunc(void(*func)(intkey,intx,inty))•回调函数内if(key==GLUT_KEY_F1)……if(key==GLUT_KEY_UP)……修饰键–Ctrl/Alt/ShiftintglutGetModifiers()如果在鼠标或键盘事件产生时修饰键被按下,该函数返回GLUT_ACTIVE_SHIFT,GLUT_ACTIVE_CTRL,GLUT_ACTIVE_ALT的逻辑与结果•可以利用单键或双键鼠标模拟三键鼠标让Ctrl+c或Ctrl+C终止程序,在键盘回调函数中if(glutGetModifiers()==GLUT_ACTIVE_CTRL)&&(key==‘c’||key==‘C’))exit(0);窗口形状的改变通过拖动窗口的角点可以改变窗口的形状和尺寸那么其中的显示内容该如何处理?•必须由应用程序重新绘制•有两种可能性•显示原来内容的一部分•通过强迫适应新窗口来显示所有内容•可能会改变了显示长宽比形状改变的可能性初始图像改变后的图像形状改变回调函数glutReshapeFunc(reshape)voidreshape(intw,inth)•返回新窗口的宽度与高度(单位:像素)•回调函数执行后自动发送刷新显示事件,触发显示回调•GLUT有一个缺省的形状改变的回调函数,调用glViewport(0,0,w,h)把视口设置为新窗口重画回调函数是放置照相机函数的恰当地方,因为当窗口首次创建时就会调用它。•当窗口形状尺寸发生改变时,可在回调函数里对观察条件进行修改例子通过保持视口和世界窗口的长宽比一样,使得物体不变形voidreshape(intw,inth){glViewport(0,0,w,h);//设置视口为整个窗口glMatrixMode(GL_PROJECTION);//调整裁剪窗口glLoadIdentity();if(w=h)//宽小于高,裁剪矩形宽度置为4gluOrtho2D(-2.0,2.0,-2.0*(GLfloat)h/
本文标题:高级计算机图形学_输入与交互_中科大
链接地址:https://www.777doc.com/doc-3878825 .html