OpenGL通过摄像机的模拟、要实现一个三维计算机图形重大转变,这是几何变换(模型转换—查看转型(两者统称为几何变换))、投影、作物转型、口变换等。同一时候,OpenGL还实现了矩阵堆栈等。理解掌握了有关坐标变换的内容,就算真正走进了精彩地三维世界。

坐标系统

OpenGL使用的是右手笛卡尔坐标系统,Z正轴垂直屏幕向外,X正轴从左到右。Y正轴从下到上。

世界坐标系:在现实世界中,全部的物体都具有三维特征,但计算机本身仅仅能处理数字。显示二维的图形,将三维物体及二维数据联系在一起的唯一纽带就是坐标。为了使被显示的三维物体数字化,要在被显示的物体所在的空间中定义一个坐标系。这个坐标系的长度单位和坐标轴的方向要适合对被显示物体的描写叙述,这个坐标系称为世界坐标系。世界坐标系是始终固定不变的。

世界坐标系以屏幕中心为原点(0, 0, 0),在OpenGL中用来描写叙述场景的坐标。

比方使用这个坐标系来描写叙述物体及光源的位置。世界坐标系,是不会被改变的。

局部坐标系:OpenGL还定义了局部坐标系的概念,所谓局部坐标系。也就是坐标系以物体的中心为坐标原点,物体的旋转或平移等操作都是环绕局部坐标系进行的,这 时,当物体模型进行旋转或平移等操作时。局部坐标系也运行对应的旋转或平移操作。

须要注意的是,假设对物体模型进行缩放操作,则局部坐标系也要进行对应的 缩放。假设缩放比例在案各坐标轴上不同。那么再经过旋转操作后,局部坐标轴之间可能不再相互垂直。不管是在世界坐标系中进行转换还是在局部坐标系中进行转 换。程序代码是同样的。仅仅是不同的坐标系考虑的转换方式不同罢了。

视坐标系:以视点为原点,以视线方向为Z轴正方向的坐标系。OpenGL会将世界坐标系先变换到视坐标系。然后进行裁剪,仅仅有在视见体之内的场景才会进入下一个阶段进行处理。

屏幕坐标系:计算机对数字化的显示物体作了加工处理后,要在图形显示器上显示。这就要在图形显示器屏幕上定义一个二维直角坐标系。这个坐标系称为屏幕坐标系。

这个坐标系坐标轴的方向通常取成平行于屏幕的边缘,坐标原点取在左下角,长度单位常取成一个象素。

三维物体的相机模拟

为了说明在三维物体到二维图象之间,须要经过什么样的变换,我们引入了相机(Camera)模拟的方式,假定用相机来拍摄这个世界,那么在相机的取景器中,就存在人眼和现实世界之间的一个变换过程。

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvc2hpbWF6aHVnZQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" align="left" width="362" height="517" alt="">

左图——相机模拟OpenGL中的各种坐标变换

从三维物体到二维图象。就如同用相机拍照一样,通常都要经历下面几个步骤:

1、将相机置于三角架上。让它对准三维景物。它相当于OpenGL中调整视点的位置。即视点变换(Viewing Transformation)。

2、将三维物体放在场景中的适当位置,它相当于OpenGL中的模型变换(Modeling Transformation),即对模型进行旋转、平移和缩放。

3、选择相机镜头并调焦,使三维物体投影在二维胶片上,它相当于OpenGL中把三维模型投影到二维屏幕上的过程。即OpenGL的投影变换 (Projection Transformation),OpenGL中投影的方法有两种,即正射投影和透视投影。为了使显示的物体能以合适的位置、大小和方向显示出来,必需要 通过投影。有时为了突出图形的一部分,仅仅把图形的某一部分显示出来。这时能够定义一个三维视景体(Viewing Volume)。正射投影时通常是一个长方体的视景体。透视投影时通常是一个棱台似的视景体。

仅仅有视景体内的物体能被投影在显示平面上,其它部分则不能。

4、冲洗底片,决定二维相片的大小。它相当与OpenGL中的视口变换(Viewport Transformation)(在屏幕窗体内能够定义一个矩形,称为视口(Viewport),视景体投影后的图形就在视口内显示)规定屏幕上显示场景的范围和尺寸。

通过上面的几个步骤。一个三维空间里的物体就能够用对应的二维平面物体表示了,也就能在二维的电脑屏幕上正确显示了。

总的来说,三维物体的显示步骤例如以下:

下图——三维物体的显示过程

OpenGL中几种变换

视点变换

视点变换确定了场景中物体的视点位置和方向,就向上边提到的,它象是 在场景中放置了一架照相机。让相机对准要拍摄的物体。

确省时,相机(即视点)定位在坐标系的原点(相机初始方向都指向Z负轴),它同物体模型的缺省位置是 一致的,显然。假设不进行视点变换,相机和物体是重叠在一起的。

运行视点变换的命令和运行模型转换的命令是同样的,想一想,在用相机 拍摄物体时,我们能够保持物体的位置不动,而将相机移离物体。这就相当于视点变换。另外,我们也能够保持相机的固定位置,将物体移离相机,这就相当于模型 转换。

这样,在OpenGL中,以逆时针旋转物体就相当于以顺时针旋转相机。因此。我们必须把视点转换和模型转换结合在一起考虑。而对这两种转换单独进行 考虑是毫无意义的。

除了用模型转换命令运行视点转换之外。OpenGL有用库还提供了gluLookAt()函数,该函数有三个变量,分别定义了视点的位置、相机瞄准方向的參考点以及相机的向上方向。该函数的原型为 :

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

该函数定义了视点矩阵,并用该矩阵乘以当前矩阵。eyex,eyey,eyez定义了视点的位置。centerx、centery和centerz变量指定了參考点的位置。该点通常为相机所瞄准的场景中心轴线上的点。upx、upy、upz变量指定了向上向量的方向。

通常。视点转换操作在模型转换操作之前发出,以便模型转换先对物体发生作用。

场景中物体的顶点经过模型转换之后移动到所希望的位置,然后再对场景进行视点定位等操作。模型转换和视点转换共同构成模型视景矩阵。

模型变换

模型变换是在世界坐标系中进行的。缺省时,物体模型的中心定位在坐标系的中心处。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);

它创建一个透视视景体。其操作是创建一个透视投影矩阵,而且用这个矩阵乘以当前矩阵。这个函数的參数仅仅定义近裁剪平面的左下角点和右上角点的三维空间坐 标,即(left,bottom,-near)和(right,top,-near);最后一个參数far是远裁剪平面的Z负值。其左下角点和右上角点空 间坐标由函数依据透视投影原理自己主动生成。near和far表示离视点的远近,它们总为正值。该函数形成的视景体例如以下图——《透视投影视景体》所看到的。


函数缺省时,视点都在原点。视线沿Z轴指向负方向。

还有一函数:

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

作是创建一个对称的透视投影矩阵,而且用这个矩阵乘以当前矩阵。

參数fovy定义视野在X-Z平面的角度,范围是[0.0,180.0]。參数aspect是投影平面宽度与高度的比率;參数zNear和Far各自是远近裁剪面沿Z负轴到视点的距离,它们总为正值。

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

例如以下图——《正射投影视景体》


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)的矩形。

视口变换

视口变换就是将视景体内投影的物体显示在二维的视口平面上。运用相机模拟方式,我们非常easy理解视口变换就是类 似于照片的放大与缩小。在计算机图形学中。它的定义是将经过几何变换、投影变换和裁剪变换后的物体显示于屏幕窗体内指定的区域内,这个区域通常为矩形。称 为视口。OpenGL中相关函数是:

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

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

注意,在实际应用中,视口的长宽比率总是等于视景体裁剪面的长宽比率。假设两个比率不相等,那么投影后的图像显示于视口内时会发生变形,例如以下图所看到的。

另外,屏幕窗口的改变一般不明显影响视口的大小。因此,在调用这个函数时,最好实时检測窗体尺寸。及时修正视口的大小,保证视口内的图像能随窗体的变化而变化,且不变形。

裁剪变换

在OpenGL中,空间物体的三维裁剪变换包括两个部分:视景体裁剪和附加平面裁剪。视景体裁剪已经包括在投影变换里,前面已述,这里不再反复。以下简单讲一下平面裁剪函数的使用方法。

在OpenGL中,除了视景体定义的六个裁剪平面(上、下、左、右、前、后)外。用户还可自己再定义一个或多个附加裁剪平面,以去掉场景中无关的目标。例如以下图——《附加裁剪平面》所看到的。


附加平面裁剪函数为:

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

参考博文

版权声明:本文博客原创文章,博客,未经同意,不得转载。

最新文章

  1. [游戏开发-学习笔记]菜鸟慢慢飞(九)- NGUI- UIWidget(官方说明翻译)
  2. android api sdk
  3. ASP.NET MVC SSO单点登录设计与实现(转载)
  4. 20145212 《Java程序设计》第1周学习总结
  5. OFFSET & FETCH
  6. 慕课linux学习笔记(六)常用命令(3)
  7. formidable上传图片
  8. ios导航栏又按钮添加图片后使其保持原色
  9. 转载 python实例手册
  10. stderr和stdout详细解说
  11. python之数据类型补充、集合、深浅copy
  12. tpot ufunc 'isnan' not supported for the input types, and the inputs could not be safely coerced to any supported types according to the casting rule ''safe''
  13. linux之more和less的基本使用
  14. django之 使用py文件操作django项目中的表
  15. GitHub 翻译之 'Hello-world' 翻译
  16. bzoj5020: [THUWC 2017]在美妙的数学王国中畅游
  17. 【OpenCV3】threshold()函数详解
  18. Matlab 基础
  19. 解读Web应用程序安全性问题的本质
  20. 如何自定义oauthauthorizationserverprovider错误信息?

热门文章

  1. ios开发多线程四:NSOperation多图下载综合案例
  2. windows程序扫雷程序设计
  3. html5-5 HTML5表单元素和内嵌框架
  4. js进阶正则表达式11RegExp的属性和方法(RegExp的属性和方法,就是RegExp对象.(点)什么的形式)(正则表达式执行之前会被编译)
  5. AndroidStudio如何配置NDK/JNI开发环境
  6. 【u024】没有上司的舞会
  7. Bootstrap3简单好用,轻松实现手机适配
  8. [SVG] Optimize SVGs for Better Performance using svgo
  9. Log4erl
  10. java十五个常用类学习及方法举例