首页 > 代码库 > glViewport()函数和glOrtho()函数的理解

glViewport()函数和glOrtho()函数的理解

glViewport()函数和glOrtho()函数的理解

  

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()函数的理解

glViewport()函数和glOrtho()函数的理解

glViewport()函数和glOrtho()函数的理解

从上述三种情况,我们可以大致了解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()函数和glOrtho()函数的理解

因为我们是用一个正方形截面的视景体截取的图像,但是拉伸到屏幕上显示的时候,就变成了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);  

   glMatrixModel(GL_PROJECTION);
   glLoadIdentity();
   glOrtho(-1.5, 1.5, -1.5, 1.5, -10, 10);
   .....
}

另外,关于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()函数的理解

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

glViewport()函数和glOrtho()函数的理解 

完整的测试程序:

 

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

void init(void)
{
    GLfloatmat_specular[] = {1.0, 1.0, 1.0, 1.0};
    GLfloatmat_shininess[] = {50.0};
    GLfloatlight_position[] = {1.0, 1.0f, 1.0, 0.0};
    GLfloatwhite_light[] = {1.0, 1.0, 1.0, 1.0};
    GLfloatlmodel_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();
    return0;
}

 

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 notfound")
ENDIF(OPENGL_FOUND)

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

ENDIF(GLUT_FOUND)

glViewport()函数和glOrtho()函数的理解

glViewport()函数和glOrtho()函数的理解