hyde
路人甲
路人甲
  • 注册日期2003-09-24
  • 发帖数555
  • QQ
  • 铜币1457枚
  • 威望0点
  • 贡献值0点
  • 银元0个
阅读:1291回复:0

OpenGL系列讲座(8)

楼主#
更多 发布于:2004-03-20 10:34
5.3 投影变换
 

投影变换是一种很关键的图形变换,OpenGL中只提供了两种投影方式,一种是正射投影,

另一种是透视投影。不管是调用哪种投影函数,为了避免不必要的变换,其前面必须加上以

下两句:

 

    glMAtrixMode(GL_PROJECTION);

    glLoadIdentity();

 

事实上,投影变换的目的就是定义一个视景体,使得视景体外多余的部分裁剪掉,最终

图像只是视景体内的有关部分。本节将详细讲述投影变换的概念以及用法。

 

5.3.1 正射投影(Orthographic Projection)

 

正射投影,又叫平行投影。这种投影的视景体是一个矩形的平行管道,也就是一个长方

体,如图2-5-9所示。正射投影的最大一个特点是无论物体距离相机多远,投影后的物体大

小尺寸不变。这种投影通常用在建筑蓝图绘制和计算机辅助设计等方面,这些行业要求投影

后的物体尺寸及相互间的角度不变,以便施工或制造时物体比例大小正确。

 

  

 

图2-5-9  正射投影视景体

 

 

    OpenGL正射投影函数共有两个,这在前面几个例子中已用过。

    一个函数是:

 

void glOrtho(GLdouble left,GLdouble right,GLdouble bottom,GLdouble top,

             GLdouble near,GLdouble far)

 

它创建一个平行视景体。实际上这个函数的操作是创建一个正射投影矩阵,并且用这个

矩阵乘以当前矩阵。其中近裁剪平面是一个矩形,矩形左下角点三维空间坐标是

(left,bottom,-near),右上角点是(right,top,-near);远裁剪平面也是一个矩形,左下角

点空间坐标是(left,bottom,-far),右上角点是(right,top,-far)。所有的near和far值同

时为正或同时为负。如果没有其他变换,正射投影的方向平行于Z轴,且视点朝向Z负轴。

这意味着物体在视点前面时far和near都为负值,物体在视点后面时far和near都为正值。

 

    另一个函数是:

 

void gluOrtho2D(GLdouble left,GLdouble right,GLdouble bottom,GLdouble top)

 

它是一个特殊的正射投影函数,主要用于二维图像到二维屏幕上的投影。它的near和

far缺省值分别为-1.0和1.0,所有二维物体的Z坐标都为0.0。因此它的裁剪面是一个左

下角点为(left,bottom)、右上角点为(right,top)的矩形。

 

 

5.3.2 透视投影(Perspective Projection)

 

透视投影符合人们心理习惯,即离视点近的物体大,离视点远的物体小,远到极点即为

消失,成为灭点。它的视景体类似于一个顶部和底部都被切除掉的棱椎,也就是棱台。这个

投影通常用于动画、视觉仿真以及其它许多具有真实性反映的方面。

OpenGL透视投影函数也有两个,其中函数glFrustum()在5.1.3节中提到过,它所形成

的视景体如图2-5-10所示。

  

 

图2-5-10  函数glFrustum()透视投影视景体

 

    这个函数原型为:

 

void glFrustum(GLdouble left,GLdouble Right,GLdouble bottom,GLdouble top,

               GLdouble near,GLdouble far);

 

它创建一个透视视景体。其操作是创建一个透视投影矩阵,并且用这个矩阵乘以当前矩

阵。这个函数的参数只定义近裁剪平面的左下角点和右上角点的三维空间坐标,即

(left,bottom,-near)和(right,top,-near);最后一个参数far是远裁剪平面的Z负值,其

左下角点和右上角点空间坐标由函数根据透视投影原理自动生成。near和far表示离视点的

远近,它们总为正值。

 

    另一个函数是:

 

void gluPerspective(GLdouble fovy,GLdouble aspect,GLdouble zNear,

                    GLdouble zFar);

 

它也创建一个对称透视视景体,但它的参数定义于前面的不同,如图2-5-11所示。其操

作是创建一个对称的透视投影矩阵,并且用这个矩阵乘以当前矩阵。参数fovy定义视野在

X-Z平面的角度,范围是[0.0,180.0];参数aspect是投影平面宽度与高度的比率;参数zNear

和Far分别是远近裁剪面沿Z负轴到视点的距离,它们总为正值。

  

 

                图2-5-11  函数gluPerspective()透视投影视景体

 

 

以上两个函数缺省时,视点都在原点,视线沿Z轴指向负方向。二者的应用实例将在后

续章节中介绍。

 

5.4  裁剪变换
 

在OpenGL中,空间物体的三维裁剪变换包括两个部分:视景体裁剪和附加平面裁剪。视

景体裁剪已经包含在投影变换里,前面已述,这里不再重复。下面简单讲一下平面裁剪函数

的用法。

除了视景体定义的六个裁剪平面(上、下、左、右、前、后)外,用户还可自己再定义

一个或多个附加裁剪平面,以去掉场景中无关的目标,如图2-5-12所示。

 

  

 

图2-5-12  附加裁剪平面和视景体

 

 

    附加平面裁剪函数为:

 

void glClipPlane(GLenum plane,Const GLdouble *equation);

 

函数定义一个附加的裁剪平面。其中参数equation指向一个拥有四个系数值的数组,这

四个系数分别是裁剪平面Ax+By+Cz+D=0的A、B、C、D值。因此,由这四个系数就能确定一

个裁剪平面。参数plane是GL_CLIP_PLANEi(i=0,1,...),指定裁剪面号。

在调用附加裁剪函数之前,必须先启动glEnable(GL_CLIP_PLANEi),使得当前所定义的

裁剪平面有效;当不再调用某个附加裁剪平面时,可用glDisable(GL_CLIP_PLANEi)关闭相

应的附加裁剪功能。

下面这个例子不仅说明了附加裁剪函数的用法,而且调用了gluPerspective()透视投影

函数,读者可以细细体会其中的用法。例程 clipball.c 如下:

 

 

例 2-6  裁剪变换例程  clipball.c

 

#include "glos.h"

 

#include <GL/gl.h>

#include <GL/glu.h>

#include <GL/glaux.h>

 

void myinit(void);

void CALLBACK myReshape(GLsizei w, GLsizei h);

void CALLBACK display(void);

 

void CALLBACK display(void)

{

    GLdouble eqn[4] = {1.0, 0.0, 0.0, 0.0};

 

    glClear(GL_COLOR_BUFFER_BIT);

 

    glColor3f (1.0, 0.0, 1.0);

    glPushMatrix();

    glTranslatef (0.0, 0.0, -5.0);

 

 /* clip the  left part of wire_sphere : x<0  */

 

    glClipPlane (GL_CLIP_PLANE0, eqn);

    glEnable (GL_CLIP_PLANE0);

 

    glRotatef (-90.0, 1.0, 0.0, 0.0);

    auxWireSphere(1.0);

    glPopMatrix();

    glFlush();

}

 

void myinit (void) {

    glShadeModel (GL_FLAT);

}

 

void CALLBACK myReshape(GLsizei w, GLsizei h)

{

    glViewport(0, 0, w, h);

    glMatrixMode(GL_PROJECTION);

    glLoadIdentity();

    gluPerspective(60.0, (GLfloat) w/(GLfloat) h, 1.0, 20.0);

    glMatrixMode(GL_MODELVIEW);

}

 

void  main(void)

{

    auxInitDisplayMode (AUX_SINGLE | AUX_RGB);

    auxInitPosition (0, 0, 500, 500);

    auxInitWindow ("Arbitrary Clipping Planes");

    myinit ();

    auxReshapeFunc (myReshape);

    auxMainLoop(display);

}

 

  

 

图 2-5-13 剪取后的网状半球体

 

 

 
喜欢0 评分0
夜落了,风静了,我喜欢一本书,一杯茶,一粒摇曳的烛光...
游客

返回顶部