OpenGL学习记录

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

OpenGL学习记录(二)---键盘控制
GLUT允许我们编写程序,在里面加入键盘输入控制,包括了普通键,和其他特殊键(如F 1,UP)。

在这一章里我们将学习如何去检测哪个键被按下,可以从GLUT里得到些什么信息,和如何处理键盘输入。

处理按键消息,我们必须使用GLUT通知窗口系统,当某个键被按下时,哪个函数将完成所要求的操作。

我们同样是调用一个函数注册相关的回调函数。

当你按下一个键后,GLUT提供了两个函数为这个键盘消息注册回调。

第一个是glutKeyb oardFunc。

这个函数是告诉窗口系统,哪一个函数将会被调用来处理普通按键消息。

普通键是指字母,数字,和其他可以用ASCII代码表示的键。

函数原型如下:
void glutKeyboardFunc(void(*func)(unsigned char key,int x,int y));
参数:
func: 处理普通按键消息的函数的名称。

如果传递NULL,则表示GLUT忽略普通按键消息。

这个作为glutKeyboardFunc函数参数的函数需要有三个形参。

第一个表示按下的键的A SCII码,其余两个提供了,当键按下时当前的鼠标位置。

鼠标位置是相对于当前客户窗口的左上角而言的。

一个经常的用法是当按下ESCAPE键时退出应用程序。

注意,我们提到过,glutMainLoo p函数产生的是一个永无止境的循环。

唯一的跳出循环的方法就是调用系统exit函数。

这就是我们函数要做的,当按下ESCAPE键调用exit函数终止应用程序(同时要记住在源代码包含头文件stdlib.h)。

下面就是这个函数的代码:
void processNormalKeys(unsigned char key,int x,int y)
{
if(key==27)
Exit(0);
}
下面让我们控制特殊键的按键消息。

GLUT提供函数glutSpecialFunc以便当有特殊键按下的消息时,你能注册你的函数。

函数原型如下:
void glutSpecialFunc(void (*func)(int key,int x,int y));
参数:
func: 处理特殊键按下消息的函数的名称。

传递NULL则表示GLUT忽略特殊键消息。

下面我们写一个函数,当一些特殊键按下的时候,改变我们的三角形的颜色。

这个函数使在按下F1键时三角形为红色,按下F2键时为绿色,按下F3键时为蓝色。

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;
}
}
上面的GLUT_KEY_*在glut.h里已经被预定义为常量。

这组常量如下:
GLUT_KEY_F1 F1 function key
GLUT_KEY_F2 F2 function key
GLUT_KEY_F3 F3 function key
GLUT_KEY_F4 F4 function key
GLUT_KEY_F5 F5 function key
GLUT_KEY_F6 F6 function key
GLUT_KEY_F7 F7 function key
GLUT_KEY_F8 F8 function key
GLUT_KEY_F9 F9 function key
GLUT_KEY_F10 F10 function key
GLUT_KEY_F11 F11 function key
GLUT_KEY_F12 F12 function key
GLUT_KEY_LEFT Left function key
GLUT_KEY_RIGHT Up function key
GLUT_KEY_UP Right function key
GLUT_KEY_DOWN Down function key
GLUT_KEY_PAGE_UP Page Up function key
GLUT_KEY_PAGE_DOWN Page Down function key
GLUT_KEY_HOME Home function key
GLUT_KEY_END End function key
GLUT_KEY_INSERT Insert function key
为了让上面processSpecialKeys函数能过编译通过,我们还必须定义,red,green,bl ue三个变量。

此外为了得到我们想要的结果,我们还必须修改renderScene函数。

...
// 所有的变量被初始化为1,表明三角形最开始是白色的。

float red=1.0, blue=1.0, green=1.0;
void renderScene(void) {
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glPushMatrix();
glRotatef(angle,0.0,1.0,0.0);
// glColor3f设置绘制三角形的颜色。

glColor3f(red,green,blue);
glBegin(GL_TRIANGLES);
glVertex3f(-0.5,-0.5,0.0);
glVertex3f(0.5,0.0,0.0);
glVertex3f(0.0,0.5,0.0);
glEnd();
glPopMatrix();
angle++;
glutSwapBuffers();
}
下面我们就该告诉GLUT,我们刚刚定义的函数用来处理,按键消息。

也就是该调用glut KeyboardFunc和glutSpecialFunc函数。

我们在main函数里调用它们。

CTRL,ALT和SHIFT
一些时候我们想知道要是一个组合键(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键。

注意,窗口系统可能会截取一些组合键(modifiers),这是就没有回调发生。

现在让我们扩充processNormalKeys,处理组合键。

按下r键时red变量被设置为0.0,当按下AT L+r时red被设置为1.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;
}
}
注意如果我们按下R键,将不会有什么发生,因为R与r键的ASCII码不同。

即这是两个不同的键。

最后就是如何检测按键CTRL+ALT+F1?。

这种情况下,我们必须同时检测两
个组合键,为了完成操作我们需要使用或操作符。

下面的代码段,使你按下CTRL+ALT+F 1时颜色改变为红色。

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;
}
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;
}
}
OpenGL学习笔记(6)第一个动画
2010-10-17 16:24 by Clingingboy, 20 visits, 网摘, 收藏, 编辑
首先再说明几个回调函数
1.glutMouseFunc用于捕获鼠标事件
2.glutKeyboardFunc用于捕获键盘事件
3.glutMotionFunc用于鼠标按下又移动鼠标的事件(MouseMove)
4.glutIdleFunc事件,当循环队列处于空闲时则触发该事件
5.glutTimerFunc单位时间内内触发事件
第一个动画
#include <stdlib.h>
static GLfloat spin = 0.0;
void display(void)
{
glClear(GL_COLOR_BUFFER_BIT);
glPushMatrix();
glRotatef(spin, 0.0, 0.0, 1.0);
glColor3f(1.0, 1.0, 1.0);
glRectf(-25.0, -25.0, 25.0, 25.0);
glPopMatrix();
glutSwapBuffers();
}
void spinDisplay(void)
{
spin = spin + 2.0;
if (spin > 360.0)
spin = spin - 360.0;
glutPostRedisplay();
}
void init(void)
{
glClearColor (0.0, 0.0, 0.0, 0.0);
glShadeModel (GL_FLAT);
}
void reshape(int w, int h)
{
glViewport (0, 0, (GLsizei) w, (GLsizei) h); glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-50.0, 50.0, -50.0, 50.0, -1.0, 1.0); glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
void mouse(int button, int state, int x, int y) {
switch (button) {
case GLUT_LEFT_BUTTON:
效果如下,犹如是动画,所以看不出来
当鼠标左键按下时则开始不断执行spinDisplay方法,这动画将使得矩形不断的旋转下面我们来看相关代码
static GLfloat spin = 0.0;
void display(void)
{
glClear(GL_COLOR_BUFFER_BIT);
glPushMatrix();
glRotatef(spin, 0.0, 0.0, 1.0);
glColor3f(1.0, 1.0, 1.0);
glRectf(-25.0, -25.0, 25.0, 25.0);
glPopMatrix();
glutSwapBuffers();
}
void spinDisplay(void)
{
spin = spin + 2.0;
if (spin > 360.0)
spin = spin - 360.0;
glutPostRedisplay();
}
每次都将spin加2,这样的话spin其实是矩形旋转度数的总和,但如何维护矩形初始化(未旋转前)的矩阵呢?
即将为旋转前的当前矩阵压入(glPushMatrix)矩阵堆栈中,然后当旋转结束后又弹出(glPopMatrix)堆栈恢复,当spin增加时,又以原始矩阵来合并,这样就不会出现什么问题了. 还有一种做法则是去掉矩阵堆栈的压入与弹出,使得spin每次都是等于2,但度数就可能会超过360,造成数字过大转换,如
glutPostRedisplay方法将调用display方法进行强制刷新
使用glutTimerFunc
glutTimerFunc回调事件只执行一次,如果想一直执行的话就需要在内部再次调该方法,下面用glutTimerFunc来替代glutIdleFunc实现同样的效果
当然首先要外部先调用一次spinDisplay方法才可以
双缓冲技术
下面这段话是转载
总体意思为两个区域一个显示,一个则负责画图,然后连续切换
在计算机上的动画与实际的动画有些不同:实际的动画都是先画好了,播放的时候直接拿出来显示就行。

计算机动画则是画一张,就拿出来一张,再画下一张,再拿出来。

如果所需要绘制的图形很简单,那么这样也没什么问题。

但一旦图形比较复杂,绘制需要的时间较长,问题就会变得突出。

让我们把计算机想象成一个画图比较快的人,假如他直接在屏幕上画图,而图形比较复杂,则有可能在他只画了某幅图的一半的时候就被观众看到。

而后面虽然他把画补全了,但观众的眼睛却又没有反应过来,还停留在原来那个残缺的画面上。

也就是说,有时候观众看到完整的图象,有时却又只看到残缺的图象,这样就造成了屏幕的闪烁。

如何解决这一问题呢?我们设想有两块画板,画图的人在旁边画,画好以后把他手里的画板与挂在屏幕上的画板相交换。

这样以来,观众就不会看到残缺的画了。

这一技术被应用到计算机图形中,称为双缓冲技术。

即:在存储器(很有可能是显存)中开辟两块区域,一块作为发送到显示器的数据,一块作为绘画的区域,在适当的时候交换它们。

由于交换两块内存
区域实际上只需要交换两个指针,这一方法效率非常高,所以被广泛的采用。

注意:虽然绝大多数平台都支持双缓冲技术,但这一技术并不是OpenGL标准中的内容。

OpenGL为了保证更好的可移植性,允许在实现时不使用双缓冲技术。

当然,我们常用的PC都是支持双缓冲技术的。

要启动双缓冲功能,最简单的办法就是使用GLUT工具包。

我们以前在main函数里面写:glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE);
其中GLUT_SINGLE表示单缓冲,如果改成GLUT_DOUBLE就是双缓冲了。

当然还有需要更改的地方——每次绘制完成时,我们需要交换两个缓冲区,把绘制好的信息用于屏幕显示(否则无论怎么绘制,还是什么都看不到)。

如果使用GLUT工具包,也可以很轻松的完成这一工作,只要在绘制完成时简单的调用glutSwapBuffers函数就可以了。

Clingingboy
关注- 14
粉丝- 49
关注博主
(请您对文章做出评价)
#include<iostream.h>
#include<math.h>
#include<windows.h>
#include<gl/glut.h>
/////////////myInit////////////////////
void myInit()
{
glClearColor(1.0,1.0,1.0,0.0);
glColor3f(0.5f,0.4f,0.9f);
glPointSize(5.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluOrtho2D(0.0,640,0.0,480);
}
///////////////////myDisplay//////////////
void myDisplay()
{
glClear(GL_COLOR_BUFFER_BIT);
glBegin(GL_POINTS);
glVertex2i(1,1);
glEnd();
glFlush();
}
/////////////myMouse///////////////////////
void myMouse(int button,int state,int x,int y)
{
if(state==GLUT_DOWN)
{
glBegin(GL_POINTS);
glVertex2i(x,480-y);
glEnd();
glFlush();
}
else if(button==GLUT_RIGHT_BUTTON)
{
glClearColor(0.8,0.6,0.7,0.0);
glClear(GL_COLOR_BUFFER_BIT);
glFlush();
}
}
/////////////////main///////////////
void main(int argc,char **argv)
{
glutInit(& argc , argv);
glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB); glutInitWindowSize(640,480); glutInitWindowPosition(100,150); glutCreateWindow("sfere");
myInit();
glutDisplayFunc(myDisplay);
glutMouseFunc(myMouse);
glutMainLoop();
}
本文来自CSDN博客,转载请标明出处:/yeqiu712/archive/2009/12/07/4958038.aspx。

相关文档
最新文档