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