zoukankan      html  css  js  c++  java
  • [转]OpenGL中glViewport和glOrtho和glFrustum

    在OpenGL中有两个比较重要的投影变换函数,glViewportglOrtho.

    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倍。

    PS:用glOrtho裁剪之后,可以把要显示的这个面(毕竟在电脑上显示出来的是二维的面,只是我们具有立体空间想象力)当成一块可以拉伸也可以压缩的布,根据glViewport的宽和高把这块布拉伸或者压缩成相应大小,这样一想裁剪(取视景体)的宽高比例如果和glViewport比例不同的话,那肯定就走形了。这样会好理解多吧。^_^
  • 相关阅读:
    PythonStudy——数据类型总结 Data type summary
    PythonStudy——可变与不可变 Variable and immutable
    PythonStudy——列表操作 List operatio
    PythonStudy——列表的常用操作 List of common operations
    PythonStudy——列表类型 List type
    PythonStudy——字符串扩展方法 String extension method
    PythonStudy——字符串重要方法 String important method
    AWT,Swing,RCP 开发
    JQuery插件机制
    最新知识网站
  • 原文地址:https://www.cnblogs.com/Aries/p/1969194.html
Copyright © 2011-2022 走看看