OpenGL Glut剖析(3)--重绘回调函数的使用

来源:互联网 发布:商标注册查询软件 编辑:程序博客网 时间:2024/05/16 07:38

http://anony3721.blog.163.com/blog/static/51197420114382654698/

OpenGL Glut剖析(3)--重绘回调函数的使用  

2011-05-03 22:29:11|  分类: 默认分类 |  标签:opengl  |字号 订阅

(一)引言

      有过Windows GDI编程经验的人都知道当窗口的尺寸发生变化时,或该窗口被另外一个窗口遮住时窗口应该发生重绘。OpenGL当然也不例外。例如下面一段程序运行后拖动窗口的边沿窗口以及里面显示的物体大小会随之变化。由于我们没有处理ON_PAINT消息,也没有编写重绘的回调函数,此时窗口中的图形没有消失说明该窗口已经进行了重绘。此时操作系统调用的是Glut中默认的重绘回调函数。OpenGL Glut剖析(2)的讲解可以看出该重绘回调函数没有改变glOrtho的平行视景体的大小,物体随窗口的拉伸而拉伸。现在的问题是如何让窗口变化后,窗口中的物体锁定纵横比,不产生变形。    

例1. 没有写reshape()函数时的情况,观察鼠标拖动窗口时调用默认重绘函数的运行结果

#include <GL/glut.h>void display(void){/* clear all pixels  */   glClear (GL_COLOR_BUFFER_BIT);/* draw white polygon (rectangle) with corners at * (0.25, 0.25, 0.0) and (0.75, 0.75, 0.0)   */   glColor3f (1.0, 1.0, 1.0);   glBegin(GL_POLYGON);      glVertex3f (0.25, 0.25, 0.0);      glVertex3f (0.75, 0.25, 0.0);      glVertex3f (0.75, 0.75, 0.0);      glVertex3f (0.25, 0.75, 0.0);   glEnd();/* don't wait!   * start processing buffered OpenGL routines  */   glFlush ();}void init (void) {/* select clearing color  */   glClearColor (0.0, 0.0, 0.0, 0.0);      /* initialize viewing values  */   glMatrixMode(GL_PROJECTION);   glLoadIdentity();   glOrtho(0.0, 1.0, 0.0, 1.0, -1.0, 1.0); //没有编写reshape()时,平行视景体应该在此初始化时调用}/* * Declare initial window size, position, and display mode  * (single buffer and RGBA).  Open window with "hello"  * in its title bar.  Call initialization routines.  * Register callback function to display graphics.  * Enter main loop and process events.*/int main(int argc, char** argv){ glutInit(&argc, argv); glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB); glutInitWindowSize (250, 250);  glutInitWindowPosition (400, 400); glutCreateWindow ("hello"); init (); glutDisplayFunc(display);  glutMainLoop(); return 0;   /* ANSI C requires main to return int. */}

(二)glut中重绘回调函数的编写

OpenGL中的重绘回调函数的编写和C#中的委托对象的初始化类似。

1) 为了让初学者明白回调函数是怎么一会事情,现在将C#的委托写出来,如下:

① 声明了一个名为 Del 的委托,该委托可以封装一个采用字符串作为参数并返回 void 的方法。

public delegate void Del(string message);  //委托实际上是一个类,该类的对象就是所谓的handler,handler是个函数指针
② Create a method for a delegate.
public static void DelegateMethod(string message)
{
    System.Console.WriteLine(message);
}

③ Instantiate the delegate. //这里的delegate指委托的类对象handler
Del handler = DelegateMethod; // 注意这里是个静态的方法,不是实例方法。

/********************顺便说说实例方法应该怎样delegate(英文的解释:v.  派 ... 为代表, 委派, 授权, 委托;n.代表)********************

MethodClass obj = new MethodClass();
Del d1 = obj.Method1; 
Del d2 = obj.Method2;
Del d3 = DelegateMethod;

//调用 allMethodsDelegate 时,将按顺序调用所有这三个方法。

Del allMethodsDelegate = d1 + d2; //类似于事件的注册
allMethodsDelegate += d3;//此时,allMethodsDelegate 在其调用列表中包含三个方法 -- Method1、Method2 和 DelegateMethod

******************************************************************************************************/
④ Call the delegate.
handler("Hello World");   //这里是手动调用,其作用类似于函数指针。如果handler是被操作系统自动调用,则称handler为回调函数。
2)glut中的窗口重绘回调函数glutReshapeFunc(reshape);的使用分两步:

①编写回调函数reshape(int width, int height)。窗口首次创建时重绘回调函数将被调用,所以该函数是放置观察函数的理想之地。可以将视景体的大小位置的设置glOrtho以及glViewport放置在此。

②在main中使用glutReshapeFunc(reshape);注册回调函数reshape(int width, int height)。当用鼠标改变窗口的尺寸以及窗口首次创建时,重绘回调函数reshape将被调用。并且新窗口的height和width将返回给函数reshape(int width, int height)。

例2  OpenGL中默认的回调函数的具体实现

前面的讨论已经说过OpengL默认的平行视景体的设置为glOrtho(-1.0, 1.0,-1.0, 1.0, -1.0, 1.0);为了突出glOrtho的设置对窗口上物体显示的影响,下面采用glOrtho(0.0, 1.0, 0.0, 1.0, -1.0, 1.0);设置平行视景体,请读者将main()函数中的glutReshapeFunc(reshape);注释起来观察显示结果,注意体会两者之间的差异。

#include "gl/glut.h"void display(void){     glClearColor(0.0,0.0,0.0,0.0);     glClear(GL_COLOR_BUFFER_BIT);//   glMatrixMode(GL_MODELVIEW); //注意加上这两句对结果没有影响,说明自动转到了MODELVIEW模式下//   glLoadIdentity();     glColor4f(1.0,1.0,1.0,1.0);     glRectf(0.25,0.25,0.75,0.75);     glFlush();}void init(void){     glClearColor(0.0, 0.0, 0.0, 0.0);     glShadeModel(GL_FLAT);   }void reshape(int w, int h){ glMatrixMode(GL_PROJECTION);  glLoadIdentity();  gluOrtho2D(0, 1, 0, 1);  //using normalized device coordinates  //glOrtho(0.0, 1.0, 0.0, 1.0, -1.0, 1.0); //function equivalent to the above gluOrth2D()  //glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0); // OpenGL中默认的glOrtho  glViewport(0, 0, (GLsizei) w, (GLsizei) h);  // 注意默认的reshape函数中的glViewport函数设置. }int main(int argc, char** argv){ glutInit(&argc, argv); glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB); glutInitWindowPosition(150, 150); glutInitWindowSize(400, 400); glutCreateWindow("OpenGL中默认的reshape()函数"); init(); glutDisplayFunc(display); glutReshapeFunc(reshape); glutMainLoop(); return 0;}


(三) glViewport(GLint x,GLint y,GLsizei width,GLsizei height)的设置对显示结果的影响

函数void glViewport(GLint x,GLint y,GLsizei width,GLsizei height)是进行视口的设置。(x,y)指定视口矩形左下角,以像素为单位。默认值为(0,0)。width, height 分别指定宽度和高度。根据窗口的实时变化重绘窗口。glViewport specifies the affine transformation of x and y from normalized device coordinates to window coordinates. 这是OpenGL官方的说明,直接说明了其核心要害。glOrtho等设置平行视景体的范围时用的坐标是归一化坐标,而屏幕上显示的眼睛能看到的形状大小是用的窗口坐标。当glOtho()设置的窗口的纵横比与视口的纵横比相等时,显示在屏幕窗口上图形不会发生形变。OpenGL中物体的显示大小发生形变根本原因在于glViewport的纵横比发生了变化而与Window size的纵横比不一致。

例3. 窗口大小变化而窗口中物体不变化的一个例子。 默认的glViewport()设置,缺省下的glViewport的width等于窗口的宽度,height等于窗口的高度。

#include "gl/glut.h"void display(void){     glClearColor(0.0,0.0,0.0,0.0);     glClear(GL_COLOR_BUFFER_BIT);     glColor4f(1.0,1.0,1.0,1.0);     glRectf(0.25,0.25,0.75,0.75);     glFlush();}void init(void){     glClearColor(0.0, 0.0, 0.0, 0.0);     glShadeModel(GL_FLAT);   }void reshape(int w, int h){ glMatrixMode(GL_PROJECTION);  glLoadIdentity();  gluOrtho2D(0, 1, 0, 1); //glViewport(0, 0, (GLsizei) w, (GLsizei) h); //注释掉此句窗口中的图形将不会随着窗口的拉伸而发生形变,因为视口的width和height没有改变glViewport(0, 0, 400, 400); //默认的glViewport的width等于窗口的宽度,height等于窗口的高度;注释掉此句对程序结果无影响}int main(int argc, char** argv){ glutInit(&argc, argv); glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB); glutInitWindowPosition(150, 150); glutInitWindowSize(400, 400); //设置窗口的宽度和高度 glutCreateWindow("OpenGL中默认的glViewport设置"); init(); glutDisplayFunc(display); glutReshapeFunc(reshape); glutMainLoop(); return 0;}


例4. 观察glViewport的设置对窗口显示结果的影响

1) glViewport中的纵横比为1:2,时对显示结果的影响

#include "gl/glut.h"void display(void){     glClearColor(0.0,0.0,0.0,0.0);     glClear(GL_COLOR_BUFFER_BIT);     glColor4f(1.0,1.0,1.0,1.0);  glRectf(0.25,0.25,0.75,0.75);     glFlush();}void init(void){     glClearColor(0.0, 0.0, 0.0, 0.0);     glShadeModel(GL_FLAT);   }void reshape(int w, int h){ glMatrixMode(GL_PROJECTION);  glLoadIdentity();  gluOrtho2D(0, 1, 0, 1); //注释掉glViewport(0, 0, 200, 400)的结果是默认的glViewport(0, 0, 400, 400) 注意对比两者的异同 glViewport(0,0,200,400); // the width of view port is half of the window size  //glViewport(0, 0, (GLsizei) w, (GLsizei) h); //resizing according to dragging}
int main(int argc, char** argv){ glutInit(&argc, argv); glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB); glutInitWindowPosition(150, 150); glutInitWindowSize(400, 400); glutCreateWindow("OpenGL中默认的reshape()函数"); init(); glutDisplayFunc(display); glutReshapeFunc(reshape); glutMainLoop(); return 0;}

OpenGL Glut剖析(3)--重绘回调函数的使用 - 阿英 - Mr.Right

 结果分析:默认的glViewport(0, 0, 400, 400)的纵横比 width:height = 1:1而此处设置的纵横比为1:2,因此显示结果是width压缩了1/2。注意纵横比1:2中较大的2对应了平行视景体中物体的实际尺寸。

2) glViewport中的纵横比为2:1,时对显示结果的影响

#include "gl/glut.h"void display(void){     glClearColor(0.0,0.0,0.0,0.0);     glClear(GL_COLOR_BUFFER_BIT);

     glColor4f(1.0,1.0,1.0,1.0);  glRectf(0.25,0.25,0.75,0.75);

     glFlush();}

void init(void){     glClearColor(0.0, 0.0, 0.0, 0.0);     glShadeModel(GL_FLAT);   }

void reshape(int w, int h){ glMatrixMode(GL_PROJECTION);  glLoadIdentity();  gluOrtho2D(0, 1, 0, 1); glViewport(0,0,400,200); // the height of view port is half of the window size  //glViewport(0, 0, (GLsizei) w, (GLsizei) h); // resizing according to dragging}

OpenGL Glut剖析(3)--重绘回调函数的使用 - 阿英 - Mr.Right

 int main(int argc, char** argv){ glutInit(&argc, argv); glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB); glutInitWindowPosition(150, 150); glutInitWindowSize(400, 400); glutCreateWindow("glViewport(0,0,400,200)"); init(); glutDisplayFunc(display); glutReshapeFunc(reshape); glutMainLoop(); return 0;}

(四)Window size的变化对显示结果的影响。

Window size对显示结果的影响是不好对其进行修正的,所以选择合适的窗口尺寸对于图形显示来说很重要

#include "gl/glut.h"void display(void){     glClearColor(0.0,0.0,0.0,0.0);     glClear(GL_COLOR_BUFFER_BIT);

     glColor4f(1.0,1.0,1.0,1.0); //注意没有显式的转到ModelView模式     glRectf(0.25,0.25,0.75,0.75);

     glFlush();}

void init(void){     glClearColor(0.0, 0.0, 0.0, 0.0);     glShadeModel(GL_FLAT);   }

void reshape(int w, int h){ glMatrixMode(GL_PROJECTION);  glLoadIdentity();  gluOrtho2D(0, 1, 0, 1); //glViewport(0,0,400,200); this setting is not a good solution to the imaging distortion //glViewport(0, 0, 200, 400); // the default view port size is the same as the window size,uncommenting this line makes no difference to the displaying result.}

OpenGL Glut剖析(3)--重绘回调函数的使用 - 阿英 - Mr.Right

 

int main(int argc, char** argv){ glutInit(&argc, argv); glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB); glutInitWindowPosition(150, 150); glutInitWindowSize(200, 400); glutCreateWindow("Window Size (200, 400)"); init(); glutDisplayFunc(display); glutReshapeFunc(reshape); glutMainLoop(); return 0;}

#include <gl/glut.h>  // 函数RenderScene用于在窗口中绘制需要的图形void RenderScene(void){//用当前清除色清除颜色缓冲区,即设定窗口的背景色glClear(GL_COLOR_BUFFER_BIT); //设置当前绘图使用的RGB颜色glColor3f(1.0f, 0.0f, 0.0f); //使用当前颜色绘制一个填充的矩形glRectf(100.0f, 150.0f, 150.0f, 100.0f); //刷新OpenGL命令队列glFlush();}// 函数ChangeSize是窗口大小改变时调用的登记函数void ChangeSize(GLsizei w, GLsizei h){if(h == 0)h = 1;//设置视区尺寸glViewport(0, 0, w, h); // 重置坐标系统,使投影变换复位glMatrixMode(GL_PROJECTION);glLoadIdentity();// 建立修剪空间的范围if (w <= h) glOrtho (0.0f, 250.0f, 0.0f, 250.0f*h/w, 1.0f, -1.0f);else glOrtho (0.0f, 250.0f*w/h, 0.0f, 250.0f, 1.0f, -1.0f);glMatrixMode(GL_MODELVIEW);glLoadIdentity();}//函数SetupRC用于初始化,常用来设置场景渲染状态void init(void){// 设置窗口的清除色为白色glClearColor(1.0f, 1.0f, 1.0f, 1.0f); }void main(void){//初始化GLUT库OpenGL窗口的显示模式glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB); // 创建一个名为GLRect的窗口glutCreateWindow("GLRect"); // 设置当前窗口的显示回调函数和窗口再整形回调函数init();glutDisplayFunc(RenderScene); glutReshapeFunc(ChangeSize); //启动主GLUT事件处理循环glutMainLoop();}


原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 包包金属刮花了怎么办 鞋子刮了黑印子怎么办 黑色鞋跟磨白了怎么办 脚穿鞋子磨起泡怎么办 脚被鞋子磨红了怎么办 脚被鞋子磨黑了怎么办 白鞋皮鞋磨了皮怎么办 小脚趾磨肿了怎么办 穿鞋小拇指磨脚怎么办 高铁东西忘了怎么办 人故意去撞车死了怎么办? 新货车上户超重怎么办 车险出保单车号填错怎么办 货车拦板变形了怎么办 行车监控看不清楚车号怎么办? 1.5米的鱼缸要怎么办 被锤子砸到手了怎么办 家里地下污水管道堵塞怎么办 家里pvc灯罩变黄怎么办 欧普吸顶灯灯罩坏了怎么办 硬盘用久了变慢怎么办 地税申报工资人员弄错怎么办 买保险保单丢了怎么办 买保险的银行卡丢了怎么办 没学过JAVA入职怎么办 磨砂皮擦了鞋油怎么办 磨破皮伤口有沙子怎么办 工行信用卡被风险锁定了怎么办 超重被超限站查住以后怎么办 银行卡输入密码次数超限怎么办 信用卡密码错误次数超限怎么办 农行密码错误次数超限怎么办 剪力墙偏心受拉怎么办 韵达快递寄丢了怎么办 重要快递送丢了怎么办 快递员送货丢了怎么办 买的快递丢失了怎么办 申通把件弄丢了怎么办 淘宝快递送丢了怎么办 我的快递丢了怎么办 顺丰快递丢件怎么办