在OpenGL中有两个比较重要的投影变换函数,glViewport和glOrtho.ortho实际上是orthographic projection正交投影的缩写。

glViewport是视口变换它是设置视口,它设置的视口的左下角,以及宽度和高度。

glOrtho是窗口变换,设置的是世界窗口俗称窗口。二维绘图来说世界窗口由gluOrth2D(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top)设定。三维绘图的世界窗口由glOrtho(left, right, bottom, top, near, far)设定。
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版)

PS:用glOrtho裁剪之后,可以把要显示的这个面(毕竟在电脑上显示出来的是二维的面,只是我们具有立体空间想象力)当成一块可以拉伸也可以压缩的布,根据glViewport的宽和高把这块布拉伸或者压缩成相应大小,这样一想裁剪(取视景体)的宽高比例如果和glViewport比例不同的话,那肯定就走形了。这样会好理解多吧。^_^

http://hi.baidu.com/einyboy/blog/item/e87120a60bd3109ed0435827.html

glViewport()和glOrtho()的理解-OpenGL相关推荐

  1. opengl中的glViewport,glOrtho,glFrustum 理解

    在刚使用opengl时,会遇到对opengles中的一些视角等理解,需要用到glViewport,glOrtho,glFrustum 等函数,下面针对这些函数做一些说明 viewport建立视口,是视 ...

  2. D49.1.0 对gluLookAt,gluPerspective和glOrtho的理解(完善篇)

    这篇文章是对<D19.1.0 对gluLookAt,gluPerspective和glOrtho的理解>的部分更正和完善. 01 gluLookAt 假定现在手上有一台单反,你可以拿着单反 ...

  3. 深入理解OpenGL之投影矩阵推导

    深入理解OpenGL之投影矩阵推导 OpenGL流水线中的投影矩阵以及坐标变换 OpenGL中,投影矩阵在Vertex shader中使用,用于变换顶点.一般和Model, View矩阵结合成MVP矩 ...

  4. D19.1.0 对gluLookAt,gluPerspective和glOrtho的理解

    今天介绍对三个函数gluLookAt,gluPerspective和glOrtho的理解.先说这两个函数有什么用,再解释怎么用,然后再说说他两有啥关系. 有什么用 01 gluLookAt gluLo ...

  5. opengl中glOrtho的理解

    根据百度词条上 glOrtho 这个函数描述了一个平行修剪空间.这种投影意味着离观察者较远的对象看上去不会变小(与透视投影相反).在3D笛卡尔坐标中想象这个修剪空间,左边和右边是最小和最大的X值,下边 ...

  6. 关于VAO,VBO和EBO的理解-OpenGL学习笔记

    本文章首发于我的个人博客,希望大家多多支持! Hi! This is Showhoop Studio! 如果要从代码层面去理解渲染管线的工作,学习使用OpenGL编程可以说是一个不错的选择.这里我将记 ...

  7. gluLookAt、glViewport()、glOrtho和gluPerspective参数分析

    一. gluLookAt和投影 void gluLookAt(GLdouble eyex,GLdouble eyey,GLdouble eyez,GLdouble centerx,GLdouble c ...

  8. 理解OpenGL中帧缓存FrameBuffer 渲染缓存RenderingBuffer

    操作都是在默认帧缓冲的渲染缓冲上进行的.默认的帧缓冲是在你创建窗口的时候生成和配置的(GLFW帮我们做了这些). 帧缓存帮助我们离屏渲染,提高渲染速度 unsigned int captureFBO; ...

  9. 新手向:如何理解OpenGL中着色器,渲染管线,光栅化等概念

    首先,光栅化(Rasterize/rasteriztion).  这个词儿Adobe官方翻译成栅格化或者像素化.没错,就是把矢量图形转化成像素点儿的过程.我们屏幕上显示的画面都是由像素组成,而三维物体 ...

最新文章

  1. HDLBits 系列(28)PS/2 mouse protocol(PS/2 packet parser)
  2. iOS UITest之加载其他应用
  3. SM01 事务代码的加锁以及解锁
  4. boost::mpl::for_each相关的测试程序
  5. 基于Swoole开发PHP扩展
  6. 图解iPhone开发新手教程
  7. linux命令date的功能,Linux 命令date
  8. python写前端和js_Python之路【第十二篇】前端之jsdomejQuery
  9. 计划任务列表 html,OpenWrt使用crontab执行计划任务
  10. ORB_SLAM3编译
  11. java毕业设计美发门店管理系统Mybatis+系统+数据库+调试部署
  12. Hibernate的一对一,一对多/多对一关联保存
  13. 【Oracle 管理员账号密码忘记的快速解决方法!十分细节!强烈建议收藏!!!】
  14. Web.config配置文件详解(转载)
  15. javascript汉字转拼音代码
  16. java list逆序_Java使用ListIterator逆序ArrayList
  17. KMP算法下,长为n的字符串中匹配长度为m的子串的复杂度为O(m+n)
  18. 全国计算机一级等级分布,计算机一级考试分布
  19. WebClient实现文件下载详解(二)
  20. 淘宝的互动项目,为什么总会刷爆你的好友圈?

热门文章

  1. 微信即时通信原理_福州5号线一期通信系统集成中标
  2. APP运营的三大核心内容
  3. 解决win10 耳机音质很差的问题
  4. 云原生之在kubernetes环境下部署wordpress
  5. Unity中协程与线程的区别
  6. laravel 黑名单功能实现
  7. Git - 常用命令使用教程
  8. Android Systrace 基础知识(9)-MainThread 和 RenderThread 解读
  9. 关于最新版CentOS-7(1804)相关说明
  10. 浪漫的花语,你知道几种!