opengl的三维与二维转换

实际上,从三维空间到二维平面,就如同用相机拍照一样,通常都要经历以下几个步骤 (括号内表示的是相应的图形学概念): 
第一步,将相机置于三角架上,让它对准三维景物(视点变换,Viewing Transformation)。 
第二步,将三维物体放在适当的位置(模型变换,Modeling Transformation)。 
第三步,选择相机镜头并调焦,使三维物体投影在二维胶片上(投影变换,Projection Transformation)。 
第四步,决定二维像片的大小(视口变换,Viewport Transformation)。 

这样,一个三维空间里的物体就可以用相应的二维平面物体表示了,也就能在二维的电脑屏幕上正确显示了。


(一)视点变换

  视点变换确定了场景中物体的视点位置和方向,就向上边提到的,它象是在场景中放置了一架照相机,让相机对准要拍摄的物体。确省时,相机(即视点)定位在坐标系的原点(相机初始方向都指向Z负轴),它同物体模型的缺省位置是一致的,显然,如果不进行视点变换,相机和物体是重叠在一起的。

  执行视点变换的命令和执行模型转换的命令是相同的,想一想,在用相机拍摄物体时,我们可以保持物体的位置不动,而将相机移离物体,这就相当于视点变换;另外,我们也可以保持相机的固定位置,将物体移离相机,这就相当于模型转换。这样,在OpenGL中,以逆时针旋转物体就相当于以顺时针旋转相机。因此,我们必须把视点转换和模型转换结合在一起考虑,而对这两种转换单独进行考虑是毫无意义的。
除了用模型转换命令执行视点转换之外,OpenGL实用库还提供了gluLookAt()函数,该函数有三个变量,分别定义了视点的位置、相机瞄准方向的参考点以及相机的向上方向。该函数的原型为:

void gluLookAt(GLdouble eyex,GLdouble eyey,GLdouble eyez,GLdouble centerx,GLdouble centery,GLdouble centerz,GLdouble upx,GLdouble upy,GLdouble upz);


  该函数定义了视点矩阵,并用该矩阵乘以当前矩阵。eyex,eyey,eyez定义了视点的位置,eye表示我们眼睛在"世界坐标系"中的位置,;centerx、centery和centerz变量指定了参考点的位置,center表示眼睛"看"的那个点的坐标,可简单理解为视线的终点,该点通常为相机所瞄准的场景中心轴线上的点;upx、upy、upz变量指定了向上向量的方向,up坐标表示观察者本身的方向,如果将观察点比喻成我们的眼睛,那么这个up则表示我们是正立还是倒立异或某一个角度在看,所看的影像大不相同,。

OpenGL与渲染管线有关的几个矩阵的形象解释 - 阿英 - Mr.Right

 

  通常,视点转换操作在模型转换操作之前发出,以便模型转换先对物体发生作用。场景中物体的顶点经过模型转换之后移动到所希望的位置,然后再对场景进行视点定位等操作。模型转换和视点转换共同构成模型视景矩阵。

变换局部坐标系的函数——glLoadIdentity()与glTranslatef()和glRotatef()

glLoadIdentity() --使用glLoadIdentity()使原点重新回到屏幕中心来

将当前的用户坐标系的原点移到了屏幕中心:类似于一个复位操作
1.X坐标轴从左至右,Y坐标轴从下至上,Z坐标轴从里至外。
2.OpenGL屏幕中心的坐标值是X和Y轴上的0.0f点。
3.中心左面的坐标值是负值,右面是正值。
   移向屏幕顶端是正值,移向屏幕底端是负值。
   移入屏幕深处是负值,移出屏幕则是正值。

glTranslatef(x, y, z)

其作用就是将你绘点坐标系的原点在当前原点的基础上平移一个(x,y,z)向量。物体是相对原点定义与绘制的,所以移动坐标原点就相当于物体的平移。将当前原点移动到(x,y,z)位置,既物体向左移动x,向上移动y,向前移动z。注意在glTranslatef(x, y, z)中,当您移动的时候,您并不是相对屏幕中心移动,而是相对与当前所在的屏幕位置。

glRotatef(angle, x, y, z)
glRotatef(angle, x, y, z)也是对坐标系进行操作。旋转轴经过原点,方向为(x,y,z),旋转角度为angle,方向满足右手定则。这里要注意物体如果不是在坐标原点,则不仅仅是简单的旋转。

  (二)模型变换

  模型变换是在模型坐标系中进行的。缺省时,物体模型的中心定位在世界坐标系的中心处。OpenGL在这个坐标系中,有三个命令,可以模型变换。

  1、模型平移

glTranslate{fd}(TYPE x,TYPE y,TYPE z);


  该函数用指定的x,y,z值沿着x轴、y轴、z轴平移物体(或按照相同的量值移动局部坐标系)。

  2、模型旋转 

glRotate{fd}(TYPE angle,TYPE x,TYPE,y,TYPE z);


  该函数中第一个变量angle制定模型旋转的角度,单位为度,后三个变量表示以原点(0,0,0)到点(x,y,z)的连线为轴线逆时针旋转物体。例如,glRotatef(45.0,0.0,0.0,1.0)的结果是绕z轴旋转45度。

  3、模型缩放

glScale{fd}(TYPE x,TYPE y,TYPE z);


  该函数可以对物体沿着x,y,z轴分别进行放大缩小。函数中的三个参数分别是x、y、z轴方向的比例变换因子。缺省时都为1.0,即物体没变化。程序中物体Y轴比例为2.0,其余都为1.0,就是说将立方体变成长方体。

  (三)投影变换 投影变换投影变换类似于选择相机的镜头

  经过模型视景的转换后,场景中的物体放在了所希望的位置上,但由于显示器只能用二维图象显示三维物体,因此就要靠投影来降低维数(投影变换类似于选择相机的镜头)。

  事实上,投影变换的目的就是定义一个视景体,使得视景体外多余的部分裁剪掉,最终进入图像的只是视景体内的有关部分。投影包括透视投影(Perspective Projection)和正视投影(Orthographic Projection)两种。

  透视投影,符合人们心理习惯,即离视点近的物体大,离视点远的物体小,远到极点即为消失,成为灭点。它的视景体类似于一个顶部和底部都被进行切割过的棱椎,也就是棱台。这个投影通常用于动画、视觉仿真以及其它许多具有真实性反映的方面。

  OpenGL透视投影函数有两个,其中函数glFrustum()的原型为:

void glFrustum(GLdouble left,GLdouble Right,GLdouble bottom,GLdouble top,GLdouble near,GLdouble far);

打通OpenGL之任督二脉---勿在浮沙筑高台 - 阿英 - Mr.Right

 


  它创建一个透视视景体。其操作是创建一个透视投影矩阵,并且用这个矩阵乘以当前矩阵。这个函数的参数只定义近裁剪平面的左下角点和右上角点的三维空间坐标,即(left,bottom,-near)和(right,top,-near);最后一个参数far是远裁剪平面的Z负值,其左下角点和右上角点空间坐标由函数根据透视投影原理自动生成。near和far表示离视点的远近,它们总为正值。

另一个透视函数是:

void gluPerspective(GLdouble fovy,GLdouble aspect,GLdouble zNear, GLdouble zFar);

打通OpenGL之任督二脉---勿在浮沙筑高台 - 阿英 - Mr.Right

 


  它也创建一个对称透视视景体,但它的参数定义于前面的不同,参数fovy定义视野在X-Z平面的角度,范围是[0.0, 180.0]。fovy这个最难理解,我的理解是,眼睛睁开的角度,即,视角的大小,如果设置为0,相当你闭上眼睛了,所以什么也看不到,如果为180,那么可以认为你的视界很广阔;参数aspect是投影平面宽度与高度的比率,就是实际窗口的纵横比,即x/y如16:9,4:3等;参数zNear和Far分别是远近裁剪面沿Z负轴到视点的距离,它们总为正值。以上两个函数缺省时,视点都在原点,视线沿Z轴指向负方向。
再解释下那个"眼睛睁开的角度fovy"是什么意思,首先假设我们现在距离物体有50个单位距离远的位置,在眼睛睁开角度设置为45时,我们可以看到,在远处一个球,现在我们将眼睛再张开点看,将"眼睛睁开的角度"设置为178(180度表示平角,那时候我们将什么也看不到,眼睛睁太大了,眼大无神)我们只看到一个点,,,,,,,,,,,,,,,,,,,,,,,,,,,因为我们看的范围太大了,这个球本身大小没有改变,但是它在我们的"视界"内太小了,
反之,我们将眼睛闭小些,改为1度看看会出现什么情况呢?在我们距离该物体3000距离远,"眼睛睁开的角度"为1时,我们似乎走进了这个球内,这个是不是类似于相机的焦距?当我们将"透视角"设置为0时,我们相当于闭上双眼,这个世界清静了,我们什么也看不到,,,,,,,,,

  正射投影,又叫平行投影。这种投影的视景体是一个矩形的平行管道,也就是一个长方体,如图五所示。正射投影的最大一个特点是无论物体距离相机多远,投影后的物体大小尺寸不变。这种投影通常用在建筑蓝图绘制和计算机辅助设计等方面,这些行业要求投影后的物体尺寸及相互间的角度不变,以便施工或制造时物体比例大小正确。

OpenGL正射投影函数也有两个,一个函数是:

void glOrtho(GLdouble left,GLdouble right,GLdouble bottom,GLdouble top, GLdouble near,GLdouble far)

打通OpenGL之任督二脉---勿在浮沙筑高台 - 阿英 - Mr.Right

 


  它创建一个平行视景体。实际上这个函数的操作是创建一个正射投影矩阵,并且用这个矩阵乘以当前矩阵。其中近裁剪平面是一个矩形,矩形左下角点三维空间坐标是(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)的矩形。
(四)视口变换。视口变换就是将视景体内投影的物体显示在二维的视口平面上。
          运用相机模拟方式,我们很容易理解视口变换就是类似于照片的放大与缩小。在计算机图形学中,它的定义是将经过几何变换、投影变换和裁剪变换后的物体显示于屏幕窗口内指定的区域内,这个区域通常为矩形,称为视口。OpenGL中相关函数是:

glViewport(GLint x,GLint y,GLsizei width, GLsizei height);


  这个函数定义一个视口。函数参数(x, y)是视口在屏幕窗口坐标系中的左下角点坐标,参数width和height分别是视口的宽度和高度。缺省时,参数值即(0, 0, winWidth, winHeight) 指的是屏幕窗口的实际尺寸大小。所有这些值都是以象素为单位,全为整型数。

  (五)裁剪变换

注意:OpenGL中的物体坐标一律采用齐次坐标,即(x, y, z, w),故所有变换矩阵都采用4X4矩阵。一般说来,每个顶点先要经过视点变换和模型变换,然后进行指定的投影,如果它位于视景体外,则被裁剪掉。最后,余下的已经变换过的顶点x、y、z坐标值都用比例因子w除,即x/w、y/w、z/w,再映射到视口区域内,这样才能显示在屏幕上。

  在OpenGL中,除了视景体定义的六个裁剪平面(上、下、左、右、前、后)外,用户还可自己再定义一个或多个附加裁剪平面,以去掉场景中无关的目标。附加平面裁剪函数为:

  1、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)关闭相应的附加裁剪功能。


阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页