OpenGL提供了两种基本类型的投影,1、透视投影:远大近小;2、正投影:不影响相对大小,一般用于建筑和CAD应用程序中。
(一)透视投影概述
(1)glFrustum(left,right,bottom,top,near,far); 该函数的参数和glOrtho()完全相同
我们的目的就是要通过glFrustum的调用来确定红色区域。
首先,图片左侧的圆点就是坐标原点(0,0,0),黄色的近平面的左下角坐标(从坐标原点往黄色平面看)用(left, bottom, -near)来指定,而近平面的右上角坐标则用(right, top, -near)来指定。为了确定红色区域,我们还缺少远平面的坐标点。实际上我们只需要知道远平面的Z坐标far就可以确定这个平面了。因为远平面的四个角的坐标可以用原点和近平面四个角的射线和远平面相交来确定。因此我们只需要设定(left,bottom, -near)、(right, top, -near)以及-far等值就可以确定红色的可视区域了,这也就构成了glFrustum函数的几个参数。
(2)gluPerspective(GLdouble fovy,GLdouble aspect,GLdouble zNear,GLdouble zFar)
gluPerspective 是 glFrustum 的一個特別情況. 你是當然可以用只用 glFrustum 的. 之前說過, view frustum 是一個任意的六面體, 使用 glFrustum 你就可以做出 任意六面體 view frustum, 但是, 實際上使用, 我們沒必要任意的六面體這麼廣的 view frustum 形狀.最常的需要, 只要一個 前寬後窄 左右相稱 上下相稱 far plane 和 near plane 平行 的 view frustum 就可以了. 這就是 gluPerspective 所提供的.
gluPerspective参数都表示什么意思
fovy,这个最难理解,我的理解是
1.眼睛睁开的角度,即,视角的大小,如果设置为0,相当你闭上眼睛了,所以什么也看不到,如果为180,那么可以认为你的视界很广阔,这两种情况下窗口中都不会有任何物体显示。
fovy相当于照相机的焦距,fovy越小则焦距拉的越近,物体在相片上显示的越大;fovy 越大则焦距拉的越远,物体在相片上现实的越小。
aspect,这个好理解,就是实际窗口的纵横比,即x/y
zNear,这个呢,表示你近处,的裁面,
zFar表示远处的裁面,
注意:gluLookAt()共有九个参数,分别是眼睛的位置,眼睛朝向的位置,以及相片朝上的方向。
这个函数是对模型矩阵进行变换(GL_MODELVIEW),而gluPerspective函数是对投影矩阵进行变换(GL_PROJECTION),这一点一定要搞清楚。
(二)投影矩阵的使用举例
例1. gluPerspective函数的使用方法
#include "gl/glut.h"
void display(void)
{
glClearColor(0.0,0.0,0.0,0.0);
glClear(GL_COLOR_BUFFER_BIT);
glColor4f(1.0,0.0,0.0,1.0);
glRectf(-10.0, 10.0, 10.0, -10.0);
glFlush();
}
void init(void)
{
glClearColor(0.0, 0.0, 0.0, 0.0);
glShadeModel(GL_FLAT);
}
void reshape(int w, int h)
{
glViewport(0, 0, (GLsizei) w, (GLsizei) h);
glMatrixMode(GL_PROJECTION); //没有使用ModelView矩阵模式,也能显示出物体。因在ModelView变换之前默认转为此模式
glLoadIdentity();
gluPerspective(120.0, (GLfloat) w/(GLfloat) h, 1.0, 20.0);
//gluPerspective(90.0, (GLfloat) w/(GLfloat) h, 1.0, 20.0); //减小fovy,发现物体变大
//gluPerspective(150.0, (GLfloat) w/(GLfloat) h, 1.0, 20.0); //增大fovy,发现物体变小
//gluPerspective(120.0, (GLfloat) w/(GLfloat) h, 15.0, 20.0); // 可看到物体,物体的大小并没有随着ZNear,ZFar而改变
//gluPerspective(120.0, (GLfloat) w/(GLfloat) h, 16.0, 20.0); // 不能看到物体
思考这个函数为什么不能看见呢?其实你要综合全文观看咯~~
glTranslatef(0,0,-15.0); //该句可以放到display()函数的一开始,注意在glTranslate之前没有显式的设置MatrixMode为GL_MODELVIEW
//默认将加上此函数的声明。
}
int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB);
glutInitWindowPosition(150, 150);
glutInitWindowSize(400, 400);
glutCreateWindow("透视投影变换");
init();
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutMainLoop();
return 0;
}
例2. 验证模型绘制时,系统默认加上glMatrixMode(GL_PROJECTION);和glLoadIdentity();
#include "gl/glut.h"
void display(void)
{
glClearColor(0.0,0.0,0.0,0.0);
glClear(GL_COLOR_BUFFER_BIT);
//glMatrixMode(GL_MODELVIEW); //注释掉这两句对结果没有影响,说明在ModelView变换之前系统默认将MatrixMode变为此模式
//glLoadIdentity();
glTranslatef(0,0,-15.0);//从reshape()中移到到此处,对执行结果没有影响
glColor4f(1.0,0.0,0.0,1.0);
glRectf(-10.0, 10.0, 10.0, -10.0);
glFlush();
}
void init(void)
{
glClearColor(0.0, 0.0, 0.0, 0.0);
glShadeModel(GL_FLAT);
}
void reshape(int w, int h)
{
glViewport(0, 0, (GLsizei) w, (GLsizei) h);
glMatrixMode(GL_PROJECTION); //这里没有使用ModelView矩阵模式,竟然也能显示出物体。我以前的认识有误
glLoadIdentity();
gluPerspective(120.0, (GLfloat) w/(GLfloat) h, 1.0, 20.0);
//glTranslatef(0,0,-15.0); //该句可以放到display()函数的一开始
}
int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB);
glutInitWindowPosition(150, 150);
glutInitWindowSize(400, 400);
glutCreateWindow("MODELVIEW矩阵的默认调用");
init();
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutMainLoop();
return 0;
}
例3.glFrustum的使用方法
#include <GL/glut.h>
void init(void)
{
glClearColor (0.0, 0.0, 0.0, 0.0);
glShadeModel (GL_FLAT);
}
void display(void)
{
glClear (GL_COLOR_BUFFER_BIT);
glColor3f (1.0, 1.0, 1.0);
glLoadIdentity (); /* clear the matrix */
/* viewing transformation */
gluLookAt (0.0, 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0); //gluLookAt将照相机向正z轴移动5个单位(从原点开始)
// glTranslatef(0.0, 0.0, -5.0); 将上面的gluLookAt注释掉换成此句对结果没有影响,因为glTranslatef将物体向-z轴方向移动5个单位
glScalef (1.0, 2.0, 1.0); /* modeling transformation */
glutWireCube (1.0);
glFlush ();
}
void reshape (int w, int h)
{
glViewport (0, 0, (GLsizei) w, (GLsizei) h);
glMatrixMode (GL_PROJECTION);
glLoadIdentity ();
glFrustum (-1.0, 1.0, -1.0, 1.0, 1.5, 20.0);
//gluPerspective(60.0,1.0,1.5,20.0); 此句和上面的glFrustum等效
//gluPerspective(60.0,1.0,4.0,6.0);// 此句和上面的ZNear = 1.5, ZFar = 20.0 效果一样,分析为什么
//gluPerspective(60.0,1.0,0.001,1000000); //前后两个剪切平面间可以显示z值[-1000000,-0.001]
glMatrixMode (GL_MODELVIEW);
}
void keyboard(unsigned char key, int x, int y)
{
switch (key) {
case 27:
exit(0);
break;
}
}
int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB);
glutInitWindowSize (500, 500);
glutInitWindowPosition (100, 100);
glutCreateWindow (argv[0]);
init ();
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutKeyboardFunc(keyboard);
glutMainLoop();
return 0;
}