在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的框框把球体的右上角装了进来。上述三种情况可以见图:

从上述三种情况,我们可以大致了解glOrtho函数的用法。

---glViewport():
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(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);
    .....
}

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()函数,我们还可以用来调整图像的分辨率。例如,保持目前的窗体大小不变,我们如果用这个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(0, 0, 2 * (GLsizei)w, 2 * (GLsizei)h); 则可以把分辨率扩大16倍。

完整的测试程序:

/*Build on ubuntu 9.04*/

#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glut.h>

void init(void)
{
    GLfloat mat_specular[] = {1.0, 1.0, 1.0, 1.0};
    GLfloat mat_shininess[] = {50.0};
    GLfloat light_position[] = {1.0, 1.0f, 1.0, 0.0};
    GLfloat white_light[] = {1.0, 1.0, 1.0, 1.0};
    GLfloat lmodel_ambient[] = {0.1, 0.1, 0.1, 1.0};
    glClearColor(0.0, 0.0, 0.0, 0.0);
    glShadeModel(GL_SMOOTH);
    glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
    glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess);
    glLightfv(GL_LIGHT0, GL_POSITION, light_position);
    glLightfv(GL_LIGHT0, GL_DIFFUSE, white_light);
    glLightfv(GL_LIGHT0, GL_SPECULAR, white_light);
    glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient);

glEnable(GL_LIGHTING);
    glEnable(GL_LIGHT0);
    glEnable(GL_DEPTH_TEST);
   
}

void display(void)
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glutSolidSphere(1.0, 20, 16);
    glFlush();
}

void reshape(int w, int h)
{
    glViewport(0, 0, (GLsizei)w, (GLsizei)h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    if (w <= h)
        glOrtho(-1.5, 1.5, -1.5 * (GLfloat)h/(GLfloat)w, 1.5 * (GLfloat)h/(GLfloat)w, -10.0, 10.0);
    else
        glOrtho(-1.5*(GLfloat)w/(GLfloat)h, 1.5*(GLfloat)w/(GLfloat)h, -1.5, 1.5, -10.0, 10.0);

glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}

int main(int argc, char **argv)
{
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH);
    glutInitWindowSize(500, 500);
    glutInitWindowPosition(100, 100);
    glutCreateWindow(argv[0]);
    init();
    glutDisplayFunc(display);
    glutReshapeFunc(reshape);
    glutMainLoop();
    return 0;
}

/*CMakeLists.txt*/

PROJECT(s5)
CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
ADD_EXECUTABLE(s5 main.cpp)

FIND_PACKAGE(OpenGL)
FIND_PACKAGE(GLUT)

IF(OPENGL_FOUND)
  INCLUDE_DIRECTORIES(${OPENGL_INCLUDE_DIR})
  TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${OPENGL_LIBRARIES})
ELSE(OPENGL_FOUND)
  MESSAGE(FATAL_ERROR "OpenGL not found")
ENDIF(OPENGL_FOUND)

IF(GLUT_FOUND)
  INCLUDE_DIRECTORIES(${GLUT_INCLUDE_DIR})
  TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${GLUT_LIBRARIES})
ELSE(GLUT_FOUND)
ENDIF(GLUT_FOUND)

参考: OpenGL编程指南(原书第6版)

glViewport()函数和glOrtho()函数的理解相关推荐

  1. glViewport()函数和glOrtho()函数的理解(转)

    在OpenGL中有两个比较重要的投影变换函数,glViewport和glOrtho. glOrtho是创建一个正交平行的视景体. 一般用于物体不会因为离屏幕的远近而产生大小的变换的情况.比如,常用的工 ...

  2. glViewport函数和glOrtho函数的理解

    在OpenGL中有两个比较重要的投影变换函数,glViewport和glOrtho. glOrtho是创建一个正交平行的视景体. 一般用于物体不会因为离屏幕的远近而产生大小的变换的情况.比如,常用的工 ...

  3. gluPerspective函数和glOrtho函数的具体用法

    我查了好多资料 按照书上的代码写的确实可以显示 自己去写代码就经常看不到画的图形了 还是搞不清楚glupetspective和glOrtho这两个函数的具体使用方法 怎样才能设置相应参数 使得所画的图 ...

  4. OpenGL函数思考-glOrtho

    OpenGL函数思考-glOrtho 函数原型: void glOrtho(GLdouble left,GLdouble right,GLdouble bottom,GLdouble top,GLdo ...

  5. c语言为什么提供函数声明机制,通过实战理解C语言精要——函数篇

    本文为作者原创,转载请注明出处,感谢您的阅读与分享,希望本文能让您有所收获. 前言 本篇博客是对C语言函数部分的重点内容和细枝末节通过实战得到的经验的总结精炼,不涵盖C语言函数的全部内容,所有提炼内容 ...

  6. 对函数指针与typedef的理解:typedef void (*sighandler_t)(int)

    文章目录 缘由 解释函数指针int (\*f)(int*); 解释typedef void(*sighandler_t)(int) 缘由 2021年9月22日在刷CS:APP的时候,邂逅了一种函数指针 ...

  7. php内核函数手册,深入理解PHP内核(五)函数的内部结构,深入理解内部结构

    深入理解PHP内核(五)函数的内部结构,深入理解内部结构 php的函数包括用户定义的函数.内部函数(print_r count...).匿名函数.变量函数($func = 'print_r'; $fu ...

  8. 带参函数_更好的理解Python第五弹函数预处理与指针

    编译预处理 预处理概念:在编译之前进行处理 在C语言中,预处理行为宏定义,文件包含,条件编译 指令 用处 # 无 #define 定义一个宏 #undef  取消定义一个已经定义的宏 #include ...

  9. 怎么理解回调函数? 回调函数合集

    网上查了一通,有点体会,特来分享与讨论. ******************************************************************************* ...

最新文章

  1. Python设计模式-命令模式
  2. mongodb索引--1亿条记录的查询从55.7秒到毫秒级别补充版
  3. 腾讯上海某实验室SQL面试题——查询最后任职信息
  4. c语言输入n个数按大小输出,输入n个整数并输出,用c语言表达
  5. ubuntu默认root密码
  6. html 打开页面光标自动选中输入框_Python自动部署码云:
  7. linux非图形界面运行vscode,linux无法启动vscode怎么办
  8. 应用系统运行监控界面_重庆悦来会展二期电力监控系统的设计与应用
  9. 尽量用iterator代替const_iterator
  10. ios sinaweibo 客户端(二)
  11. RTP 包格式 详细解析
  12. Python读取 csv文件中文乱码处理
  13. 使用FlashCS6制作cocos2d-x动作脚本的思路整理
  14. 架构师职位常见面试题
  15. 5G适合py还是java,5G比4G到底有啥好处?看完就彻底明白了
  16. SpringMVC入门运行成功的实例(一)
  17. electron-rebuild
  18. 如何查看GPU的计算能力?
  19. 在Windows 记事本中快速选中大量文本的方法
  20. flink故障恢复的流程(从检查点恢复状态)

热门文章

  1. JavaScript设计模式(三):结构型设计模式-外观模式、适配器模式、代理模式、装饰者模式、桥接模式、组合模式、享元模式
  2. MySQL 优化居然有这么多技巧?
  3. 如何创建.babelrc文件
  4. python中fib是啥算式函数_python常用函数简介
  5. 腾达fh450虚拟服务器,腾达(Tenda)FH450与FH451与F450与F451无线路由器设置上网
  6. 计算机程序员的表白(转)
  7. Python获取Windows软件安装路径
  8. 来自AI+光学技术的创新|如何用眼镜让色盲患者重新看到世界的色彩?
  9. vue 中定时器的使用全解
  10. 企业网站的搜索引擎优化