glViewport()函數和glOrtho()函數的理解(轉)


轉:http://www.cnblogs.com/yxnchinahlj/archive/2010/10/30/1865298.html

 

摘要:glOrtho相當指定圖框的大小,由此會使得圖框里的圖形形狀變化,因為如果圖框越寬那么圖形的寬度越窄。即可認為glOrtho定義的是剪裁面(圖框),是從空間無限坐標面截取的一個剪裁面,那么glViewPort也是類似的,只不過是從glOrtho定義的剪裁面中再剪裁一個區域,顯示的內容只在這個區域內顯示。這里有點不一樣的是glViewPort實際上是指定寬口的實際像素寬度高度。(區別,glOrtho指定世界坐標,glViewPort指定像素)(實際上這兩個函數都用於平行投影而非透視投影)。

     一、gluOtho()

        這個函數是定義剪裁面,何謂剪裁面,我這樣理解,我們是在一個無限的空間里繪圖,因為坐標是 可以隨便指定的,隨便在哪個坐標繪圖,但是我們可以通過定一個剪裁面,也就是說,有一架照相機,盡管沿途風景很多,但是鏡頭只能拍到一定的范圍,這個范圍 就是我們的剪裁面,我們能顯示的就是這個剪裁面。

     二、glViewPort()

        這個函數跟上面的相似,但是我們發現上面的指定一個剪裁面后,是在我們定義的窗口的整個窗口中顯示我們剪裁出來的面,而這個函數就是為了在一部分中顯我們要顯示的剪裁面,即,我們先取景(就是用gluOrtho()剪出來那個),然后在我們定義的窗口中選一個區域來顯示這個取好的景。

 

在OpenGL中有兩個比較重要的投影變換函數,glViewport和glOrtho。

glOrtho是 創建一個正交平行的視景體。 一般用於物體不會因為離屏幕的遠近而產生大小的變換的情況(圖形學中的平行投影和透視投影,glFrustum用於透視投影)。比如,常用的工程中的制圖等。需要比較精確的顯示。 而作為它的對立情況, 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函數只是負責使用什么樣的視景體來截取圖像並不負責使用某種規則把圖像呈現在屏幕上。(這句話不能理解)

glBegin(GL_QUADS);

glColor3f(1, 0, 0);
       glVertex3f(-1, 1, 0);
       glVertex3f(-1, -1, 0);
       glVertex3f(1, -1, 0);
       glVertex3f(1, 1, 0);

glEnd();

比如畫一個矩形框,然后glOrtho(-2, 2, -2, 2, -10, 10);如圖:[OpenGL]glViewport()函數和glOrtho()函數的理解(轉)

然后glOrtho(-2, 2, -3, 3, -10, 10);如圖

[OpenGL]glViewport()函數和glOrtho()函數的理解(轉)

  可以看到他們的不同,實際上它是按等比例的,比如矩形長度是2,但視圖窗口是4,所以占1/2。

 

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);  

    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 - 閑逛

完整的測試程序:

 

#include

#include

#include

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;

}

 

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)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM