当前位置:首页 期刊杂志

OpenGL中三维图形的显示过程

时间:2024-05-04

文/徐凤雪

(山东师范大学 山东省济南市 250358)

1 引言

在人们日常生活的现实世界中,所有的物体都具有三维特性,但是计算机只能处理离散的数据,在屏幕上显示二维图形。所以,将三维图形显示在二维平面上是一个复杂的问题,而唯一能在三维物体和二维数据之间建立起关联的就是坐标系统。因此,在整个三维图形显示系统中,可以定义不同的坐标系统,通过一系列三维变换,实现将三维图形显示在二维平面上。为了便于理解,引入照相机成像的模拟过程,形象地展示出从三维物体到二维数据之间所经过的各种变换。OpenGL作为一种三维图形编程接口,为用户提供了多种简明的图形绘制功能,它可以理解为一种状态机,通过矩阵堆栈的形式来获取用户的输入并修改自己当前的状态,从而实现相应的变换和输出。

2 三维图形显示、变换管线

2.1 三维图形坐标系统

前面说到,要通过不同的坐标系统来将三维物体与二维平面的显示联系起来,需要设立不同的坐标系统,将物体的三维空间特性映射到二维平面上,同时还能保留其三维特点,OpenGL为此设立了包括模型坐标系、世界坐标系、观察坐标系和成像面坐标系、视口坐标系在内的坐标系统,用以完成整个三维图形的显示、变换过程。如图1所示。

(1)世界坐标系(X,Y,Z)是要显示物体所在空间的一个总的基准坐标系,用于定义其他的坐标点及坐标系,作为其他坐标系之间转换的桥梁,世界坐标系是始终保持不变的。

(2)模型坐标系(Xm,Ym,Zm)也称局部坐标系,其原点位于三维物体的中心,主要用于描述物体的几何特性。

(3)观察坐标系(Xv,Yv,Zv)是为了观察物体投影在二维平面上的成像而设立的坐标系,其坐标原点就是视点的位置,相当于人们的眼睛,当从不同的角度和距离来观察物体,就会在成像面上形成不同的图像。观察坐标系作为模型坐标系和世界坐标系之间转换的桥梁,可以简化三维物体在投影面成像的数学推导和计算过程。

(4)成像面坐标系就是在投影平面上所建立的一个二维坐标系,用于显示三维物体经过投影变换之后的二维图像信息。

(5)视口坐标系也即设备坐标系,是物体最终显示的屏幕坐标系统,不同的设备有不同的显示。

此外,在设备屏幕显示最终图像之前,还需要进行一步规范化设备坐标系的变换,规范化设备坐标系也是一个二维坐标系,主要用于规范不同分辨率的设备显示,它独立于具体规格的设备,坐标范围为0-1。

2.2 三维物体的相机模拟

整个三维物体的显示过程,可以用照相机拍照的形式来模拟生成。OpenGL就是在其内部设定了一个虚拟摄像机,来模拟物体的显示过程。

如图2所示,照相机拍照与计算机生成图像的步骤如下:

(1)将相机固定在三脚架上,令其对准要拍摄的物体,相机的位置即视点位置——观察坐标系的原点,从被摄物体到相机的方向为Z轴,手持相机的正上方为Y轴,最终通过右手定则确定X轴

图1:三维图形坐标系统

的方向。调整相机的位置就是调整视点的位置,这个过程对应于OpenGL中的视图变换。

(2)相机的位置确定好之后,有时还需要改变物体的位置,这个过程对应于从模型坐标系到世界坐标系的转化,对应于OpenGL中的模型变换。

(3)要想将具体的景物定格在相机内部,需要调整焦距和相关内参数,然后按下快门,这个过程对应于OpenGL中利用观察坐标系进行的投影变换。

(4)照片拍完之后需要冲洗底片,也就是确定照片的尺寸,即分辨率。这个过程在OpenGL中称为视口变换,用于设定最终显示图形的窗口在二维屏幕上的大小和位置。

2.3 三维图形显示流程

OpenGL中三维物体呈现在二维平面上的过程变换可以分为如图3的几步。

3 OpenGL中所对应的变换函数

OpenGL中各种变换函数的功能是通过矩阵相乘的形式来实现的,每当OpenGL调用一个变换函数,就会生成一个4×4阶的矩阵,该变换矩阵与矩阵堆栈中现存矩阵相乘,形成一个新的现存矩阵,当该新的现存矩阵与所绘制的某一顶点相乘时,该矩阵所对应的变换功能,就会作用在要绘制的顶点上,从而实现相应的变换。

3.1 模型变换

模型变换对应于拍照过程中设定物体的位置,也就是将物体放在世界坐标系中的某一合适坐标点。OpenGL提供了三个接口函数来实现此变换操作,它们为glTranslatef、glRotatef和glScalef,分别对应于平移、旋转和缩放变换。这三个变换函数调用后,便会生成一个变换矩阵,该矩阵与当前矩阵相乘,作用于要绘制的图形,使得图形在世界坐标系中的位置或形状发生改变。

图2:照相机模拟成像过程

需要注意的是,在OpenGL中,若未指定物体的具体位置,即不做任何变换时,物体本身的模型坐标系和世界坐标系是完全重合的。因此,当我们对三维物体施加几何变换操作时,可以有两种理解方式。第一种理解是,可以看做整个场景中不存在模型坐标系,绘制图形时设定的顶点坐标直接在世界坐标系中,三种模型变换也是直接作用在物体顶点上,从而实现物体在整个场景(世界坐标系)中的位置变换。第二种理解是,绘制模型时给出的顶点坐标都是针对物体本身的模型坐标系而言,而上述三种变换是作用于模型坐标系与世界坐标系之间的变换,即对整个模型坐标系在世界坐标系中进行了平移、旋转和缩放,而顶点坐标始终在模型坐标系中。为了更好地将三维图形的显示过程理解清楚,大多数情况下采用第二种理解方式。

3.2 视图变换

视图变换对应于拍照过程中设置相机的摆放位置及拍摄方向,即建立观察坐标系。在OpenGL中设立观察坐标系的函数是gluLookAt(GLdouble eyex,GLdouble eyey,GLdouble eyez,GLdouble atx,GLdouble aty,GLdouble atz,GLdouble upx,GLdouble upy,GLdoubleupz)。其中,(eyex,eyey,eyez)确定视点的位置,(atx,aty,atz)确定拍摄物体的位置,从点(atx,aty,atz)到点(eyex,eyey,eyez)为观察坐标系z轴的方向,(upx,upy,upz)为观察坐标系y轴的三个分量,最终通过右手定则确定x轴的方向。

根据物理学基本原理:运动是相对的,可以得到在整个拍摄过程中,三维物体和视点的位置也是一个相对的关系,对于同样的显示效果,既可以通过模型变换来实现,也可以通过视图变换来实现。比如,要想让物体与视点的距离减少3个单位,可以保持物体位置不变,使用gluLookat(0,0,-3,0,0,0,0,1,0)函数使得相机靠近物体,也可以保持相机不动,调用gltranslate(0,0,3)函数使得物体向相机移动三个单位距离,最终的显示效果是一样的。然而,为了物理意义上的清晰以及程序的可读性,OpenGL中将模型变换和视图变换区分开来,当需要改变物体的几何属性时,使用模型变换,当需要指定相机的位置和方向时,则采用视图变换。此外,需要注意的是,OpenGL在其内部把上述两种变换合并为一个:模型视图变换,且使用一个模型视图矩阵来完成。在图形绘制过程中,无论是进行模型变换还是视图变换,都要先调用glMatrixMode(GL_MODEVIEW)函数,将OpenGL当前的矩阵堆栈设置为模型视图状态,再将相对应的变化函数乘到当前的模型视图矩阵上。还应注意的是,OpenGL的矩阵相乘都是采用右乘的形式,因此实际呈现的变换顺序与代码中写的变换顺序是相反的。因此,在编写程序时,要考虑好各种变换之间的前后顺序与最终呈现结果之间的关系,以避免相关问题的混淆。

图3:三维图形显示流程图

3.3 投影变换

投影变换的主要作用就是在人眼和三维物体之间建立一个视截体,将位于视截体内部的物体投影到成像面上,而舍弃视截体外的部分。视截体中离视点近的面称为近裁剪面,远的为远裁剪面。通常来讲,投影方式分为平行投影和透视投影两种。

3.3.1 平行投影

在OpenGL中一般使用 glOrtho()函数来设定三维平行投影模式。该函数调用后,会创建一个长方体形状的视截体,其中近裁剪面和远裁剪面都是一个矩形,各个函数参数定义了整个视截体的位置和形状。调用该函数后,OpenGL就会自动创建一个平行投影矩阵,该矩阵与当前的投影矩阵相乘,作用于要绘制的物体坐标,产生相应的投影效果。

3.3.2 透视投影

OpenGL提供了两个透视变换函数。第一个为glFrustum (GLdouble left,GLdouble right,GLdouble bottom,GLdouble top,GLdouble near,GLdouble far)。该函数创建了一个近裁剪面小于远裁剪面的四棱台形状的视截体,其前四个参数只确定了近裁剪面的大小,near确定了近裁剪面离视点的距离,OpenGL内部通过透视原理和最后一个参数far自动计算出远裁剪面的具体位置和形状。同理,该函数调用后,会自动生成一个投影变换矩阵用于三维物体的透视投影。

OpenGL还提供了另外一个透视投影函数gluPerspective (GLdouble fovy,GLdouble aspect,GLdouble near,GLdouble far)。此函数也是创建了一个四棱台形状的视截体,但其中的参数与上一个函数不同。fovy确定了Y-Z平面的观察角度,aspect为投影平面的宽高比,near和far则表示近、远裁剪面到视点的距离,它们的值总是大于0。该函数完全定义了整个视截体的形状和位置,比起glFrustum函数使用起来更加理想。与模型视图变换类似,在调用具体的投影变换函数之前,也要通过glMatrixMode(GL_PROJECTION)函数将当前的矩阵堆栈指定为投影变换状态。

3.4 视口变换

视口变换直接决定了所绘制的图形在屏幕上最终显示的大小和位置。实际上,视口就是最终人们在二维屏幕上所观察到的图形显示窗口,被观察物体经过前面的一系列变换后,其各顶点坐标已经转换到规范化设备坐标系,这一步由OpenGL自动完成,后面再由规范化设备坐标转换到视口坐标系中的过程就是视口变换。OpenGL提供了视口变换函数glViewport,其前两个参数定义了二维显示窗口的左下角在屏幕上坐标位置,后两个参数则定义了窗口的宽和高。此函数调用后,便可确定最终显示图形的大小和位置。在视口变换中需要注意的是,设置视口的宽度和高度时,应当使其纵横比和投影变换中的纵横比保持一致,这样才能保证显示出来的图像不会压扁或者拉伸。并且,在窗口的大小发生改变时,也应当及时调整视口的大小,否则绘制的图形会随着窗口形状的变化而变化。

4 结语

三维图形的显示过程是整个图形渲染管线的核心,其中的各种变换实际上包含着很多复杂的数学原理和推导计算过程,编程开发人员只有正确理解整个三维变换的原理和过程,才能更加熟练和高效的使用OpenGL提供的各个接口函数。

免责声明

我们致力于保护作者版权,注重分享,被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自各大过期杂志,内容仅供学习参考,不准确地方联系删除处理!