在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的框框把球體的右上角裝了進來。上述三種狀況能夠見圖: ubuntu
從上述三種狀況,咱們能夠大體瞭解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); oop
....
}
這樣是能夠看到一個正常的球體的。可是,若是咱們建立窗體時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*/ ui
glMatrixModel(GL_PROJECTION);
glLoadIdentity();
glOrtho(-1.5, 1.5, -1.5, 1.5, -10, 10);
.....
} it
OK. 若是你能看明白我寫的內容。你可能對glViewport函數有個大體的瞭解。 io
不過,咱們採用上面的辦法,就是隻使用了原來屏幕的一部分(寬度從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); List
....
} rust
另外,關於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倍。 model
而若是再修改一下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)