OpenGL的glOrtho平行投影函数详解[转]

摘要:
glortho函数可以将当前视觉空间设置为正交投影空间。GlOrtho用于创建正交和平行视景。与之相反,glFrustum产生了透视投影。首先,分别了解glOrtho的功能。以上三种情况可以在图中看到:从上述三种情况中,我们可以大致了解glOrtho函数的用法。glOrtho函数只负责使用什么视觉对象捕捉图像,而不负责使用某些规则在屏幕上渲染图像。然后只能修改glOrtho函数。

glortho函数可以将当前的可视空间设置为正投影空间。基参数的意义如图,如果绘制的图空间本身就是二维的,可以使gluOrtho2D.他的使用类似于glOrtho

原型是:

voidglOrtho(GLdoubleleft,
                   GLdoubleright,
                   GLdoublebottom,
                   GLdoubletop,
                   GLdoublenear,
                   GLdoublefar);

在OpenGL中有两个比较重要的投影变换函数,glViewport和glOrtho。

glOrtho是创建一个正交平行的视景体。 一般用于物体不会因为离屏幕的远近而产生大小的变换的情况。比如,常用的工程中的制图等。需要比较精确的显示。 而作为它的对立情况, glFrustum则产生一个透视投影。这是一种模拟真是生活中,人们视野观测物体的真实情况。例如:观察两条平行的火车到,在过了很远之后,这两条铁轨是会相交于一处的。还有,离眼睛近的物体看起来大一些,远的物体看起来小一些。

glOrtho(left, right, bottom, top, near, far), left表示视景体左面的坐标,right表示右面的坐标,bottom表示下面的,top表示上面的。这个函数简单理解起来,就是一个物体摆在那里,你怎么去截取他。这里,我们先抛开glViewport函数不看。先单独理解glOrtho的功能。 假设有一个球体,半径为1,圆心在(0, 0, 0),那么,我们设定glOrtho(-1.5, 1.5, -1.5, 1.5, -10, 10);就表示用一个宽高都是3的框框把这个球体整个都装了进来。  如果设定glOrtho(0.0, 1.5, -1.5, 1.5, -10, 10);就表示用一个宽是1.5, 高是3的框框把整个球体的右面装进来;如果设定glOrtho(0.0, 1.5, 0.0, 1.5, -10, 10);就表示用一个宽和高都是1.5的框框把球体的右上角装了进来。上述三种情况可以见图:

glViewport()函数和glOrtho()函数的理解(转) - WAYNE - 闲逛 

glViewport()函数和glOrtho()函数的理解(转) - WAYNE - 闲逛 

glViewport()函数和glOrtho()函数的理解(转) - WAYNE - 闲逛 

从上述三种情况,我们可以大致了解glOrtho函数的用法。glOrtho函数只是负责使用什么样的视景体来截取图像,并不负责使用某种规则把图像呈现在屏幕上。

glViewport主要完成这样的功能。它负责把视景体截取的图像按照怎样的高和宽显示到屏幕上。

比如:如果我们使用glut库建立一个窗体:glutInitWindowSize(500, 500); 然后使用glutReshapeFunc(reshape); reshape代码如下:

void reshape(int width, int height)

{

    glViewport(0, 0, (GLsizei)width, (GLsizei)height);

    glMatrixModel(GL_PROJECTION);

    glLoadIdentity();

    glOrtho(-1.5, 1.5, -1.5, 1.5, -10, 10);

    ....

}

这样是可以看到一个正常的球体的。但是,如果我们创建窗体时glutInitWindowSize(800, 500),那么看到的图像就是变形的。上述情况见图。 

glViewport()函数和glOrtho()函数的理解(转) - WAYNE - 闲逛

因为我们是用一个正方形截面的视景体截取的图像,但是拉伸到屏幕上显示的时候,就变成了glViewport(0, 0, 800, 500);也就是显示屏变宽了, 倒是显示的时候把一个正方形的图像“活生生的给拉宽了”。就会产生变形。这样,就需要我们调整我们的OpenGL显示屏了。我们可以不用800那么宽,因为我们是用的正方形的视景体,所以虽然窗体是800宽,但是我们只用其中的500就够了。修改一下程序。

void reshape(int width, int height)

{

    int dis = width < height ? width : height;

    glViewport(0, 0, dis, dis);   /*这里dis应该是500*/

    glMatrixModel(GL_PROJECTION);

    glLoadIdentity();

    glOrtho(-1.5, 1.5, -1.5, 1.5, -10, 10);

    .....

}

glViewport()函数和glOrtho()函数的理解(转) - WAYNE - 闲逛

OK。如果你能看明白我写的内容。你可能对glViewport函数有个大致的了解。

不过,我们采用上面的办法,就是只使用了原来屏幕的一部分(宽度从501到800我们没有用来显示图像)。如果我们想用整个OpenGL屏幕显示图像,但是又不使图像变形怎么办?

那就只能修改glOrtho函数了。也就是说,我们使用一个和窗体一样比例的视景体(而不再是正方形的视景体)来截取图像。例如,对于(800, 500)的窗体,我们使用glOrtho(-1.5 * 800/500, 1.5 * 800/500, -1.5, 1.5, -10, 10),就是截取的时候,我们就使用一个“扁扁”的视景体截取,那么,显示的到OpenGL屏幕时(800, 500),我们只要正常把这个扁扁的截取图像显示(扁扁的截取图像是指整个截取的图像,包括球形四周的黑色部分。 球形还是正常圆形的),就可以了。如:

void reshape(int width , int height)

{

    glViewport(width, height); //按照窗体大小制作OpenGL屏幕

    glMatrixMode(GL_PROJECTION);

    glLoadIdentity();

    if (width <= height)

        glOrtho(-1.5, 1.5, -1.5 * (GLfloat)height/(GLfloat)width, 1.5 * (GLfloat)height/(GLfloat)width, -10.0, 10.0);

    else

        glOrtho(-1.5*(GLfloat)width/(GLfloat)height, 1.5*(GLfloat)w/(GLfloat)h, -1.5, 1.5, -10.0, 10.0);

    ....

}

glViewport()函数和glOrtho()函数的理解(转) - WAYNE - 闲逛

另外,关于glViewport()函数,我们还可以用来调整图像的分辨率。例如,保持目前的窗体大小不变,我们如果用这个size来只显示整个物体的一部分,那么图像的分辨率就必然会增大。例如:

void reshape(int w, int h)

{

    glViewport(0, 0, (GLsizei)w, (GLsizei)h);

    glMatrixMode(GL_PROJECTION);

    glLoadIdentity();

    if (w <= h)

        glOrtho(0, 1.5, 0, 1.5 * (GLfloat)h/(GLfloat)w, -10.0, 10.0);

    else

        glOrtho(0, 1.5*(GLfloat)w/(GLfloat)h, 0, 1.5, -10.0, 10.0);

}

可以把分辨率扩大4倍。

glViewport()函数和glOrtho()函数的理解(转) - WAYNE - 闲逛

而如果再修改一下glViewport(0, 0, 2 * (GLsizei)w, 2 * (GLsizei)h); 则可以把分辨率扩大16倍。

glViewport()函数和glOrtho()函数的理解(转) - WAYNE - 闲逛

完整的测试程序:

 1 /*Build on ubuntu 9.04*/
 2 #include <GL/gl.h>
 3 #include <GL/glu.h>
 4 #include <GL/glut.h>
 5 void init(void)
 6 {
 7     GLfloat mat_specular[] = {1.0, 1.0, 1.0, 1.0};
 8     GLfloat mat_shininess[] = {50.0};
 9     GLfloat light_position[] = {1.0, 1.0f, 1.0, 0.0};
10     GLfloat white_light[] = {1.0, 1.0, 1.0, 1.0};
11     GLfloat lmodel_ambient[] = {0.1, 0.1, 0.1, 1.0};
12     glClearColor(0.0, 0.0, 0.0, 0.0);
13     glShadeModel(GL_SMOOTH);
14     glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
15     glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess);
16     glLightfv(GL_LIGHT0, GL_POSITION, light_position);
17     glLightfv(GL_LIGHT0, GL_DIFFUSE, white_light);
18     glLightfv(GL_LIGHT0, GL_SPECULAR, white_light);
19     glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient);
20     glEnable(GL_LIGHTING);
21     glEnable(GL_LIGHT0);
22     glEnable(GL_DEPTH_TEST);
23 }
24 
25 void display(void)
26 {
27     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
28     glutSolidSphere(1.0, 20, 16);
29     glFlush();
30 }
31 
32 void reshape(int w, int h)
33 {
34     glViewport(0, 0, (GLsizei)w, (GLsizei)h);
35     glMatrixMode(GL_PROJECTION);
36     glLoadIdentity();
37     if (w <= h)
38         glOrtho(-1.5, 1.5, -1.5 * (GLfloat)h/(GLfloat)w, 1.5 * (GLfloat)h/(GLfloat)w, -10.0, 10.0);
39     else
40         glOrtho(-1.5*(GLfloat)w/(GLfloat)h, 1.5*(GLfloat)w/(GLfloat)h, -1.5, 1.5, -10.0, 10.0);
41 
42     glMatrixMode(GL_MODELVIEW);
43     glLoadIdentity();
44 }
45 
46 int main(int argc, char **argv)
47 {
48     glutInit(&argc, argv);
49     glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH);
50     glutInitWindowSize(500, 500);
51     glutInitWindowPosition(100, 100);
52     glutCreateWindow(argv[0]);
53     init();
54     glutDisplayFunc(display);
55     glutReshapeFunc(reshape);
56     glutMainLoop();
57     return 0;
58 }
59 
60 /*CMakeLists.txt*/
61 PROJECT(s5)
62 CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
63 ADD_EXECUTABLE(s5 main.cpp)
64 FIND_PACKAGE(OpenGL)
65 FIND_PACKAGE(GLUT)
66 IF(OPENGL_FOUND)
67 INCLUDE_DIRECTORIES(${OPENGL_INCLUDE_DIR})
68 TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${OPENGL_LIBRARIES})
69 ELSE(OPENGL_FOUND)
70 MESSAGE(FATAL_ERROR "OpenGL not found")
71 ENDIF(OPENGL_FOUND)
72 IF(GLUT_FOUND)
73 INCLUDE_DIRECTORIES(${GLUT_INCLUDE_DIR})
74 TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${GLUT_LIBRARIES})
75 ELSE(GLUT_FOUND)
76 ENDIF(GLUT_FOUND)

转至:http://blog.csdn.net/why_study/article/details/8204827

免责声明:文章转载自《OpenGL的glOrtho平行投影函数详解[转]》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇Windows下DVWA安装指南国内外免费PHP开源建站程序下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

C#+Winform开发窗体程序

第一章:WinForm基础 一、概述 1、Windows Form(简称WinForm) 是微软.NET平台下用于开发"图形界面"应用程序的组件。   2、C/S架构 客户机(Client)/服务器(Server),是软件系统体系结构。 通过它可以充分利用两端硬件环境的优势,将任务合理分配到Client端和Server端来实现,降低了系统的通讯开销。  ...

OpenGL教程一

引自:https://blog.csdn.net/u013654125/article/details/73613644 GLEW, GLFW和GLM介绍 现在你有了工程,就让我们开始介绍下工程所用到的开源库和为啥需要这些。 The OpenGL Extension Wrangler (GLEW)是用来访问OpenGL 3.2 API函数的。不幸的是你不能...

Qt之手动布局

简述 手动布局,可以实现和水平布局、垂直布局、网格布局等相同的效果,也可实现属于自己的自定义布局,当窗体缩放时,控件可以随之变化。 其对于坐标系的建立有严格要求,纯代码思维,使用复杂,不易维护,所以一般不建议使用。 下面我们以简单的例子来讲解如何使用。 简述 事件 垂直布局 简略图 效果 源码 水平布局 效果 源码 总结 事件 在Qt之布...

OpenGL实践之--窗口创建

  作为一个图形接口的OpenGL在使用严重依赖窗口,必须在窗口中绘制图形,但是自身并没有包含窗口及其相关内容。因此,学习OpenGL就必须了解一种窗口系统,不同的操作系统提供的创建窗口的API都不相同,为了避免学习OpenGL时必须去学习一整套的窗口系统的不便,简单应用可以使用GLUT(OpenGL Utility Toolkit),是一套和窗口系统无关...

winform窗体 控件【菜单和工具栏控件】【容器控件】

  winform的菜单栏和工具栏      1.ContextMenuStrip   -- 右键菜单        可以绑定在任何一个控件上,添加操作快捷键,并可以设置多层       每行相当于一个按钮,输入-可添加分割线       将控件拖入窗体——添加操作名称——找到要进行右键操作的控件的 ContextMenuStrip 属性——委托    ...

QT入门-在窗体中添加按钮以及对窗体进行设置

1) QT中,按钮类叫做QPushButton。在mywidget.h的MyWidget类的私有变量中: QPushButton b1; 或者QPushButton* b2;按住F4可以直接跳到.cpp文件。 2) 按钮初始化:在窗口类的构造函数里初始化即可。b2=new QPushButton(…)选中按F1可以查看构造函数以及其参数。 QPushBu...