分享
 
 
 

Linux下的OpenGL编程

王朝system·作者佚名  2006-11-24
窄屏简体版  字體: |||超大  

OpenGL是一个工业标准的三维计算机图形软件接口,它由SGI公司发布并广泛应用于Unix、OS/2、Windows/NT等多种平台,当然也包括Linux。在Windows/NT平台上,一般的开发工具如VC、BC、Fortran Powerstation等都支持直接的OpenGL应用的开发;在商用Unix平台上,Motif同样很好的支持OpenGL(毕竟OpenGL最初是工作站上的东西);那么在Linux上呢?

本文不着力于OpenGL编程的方法和技巧,而是把重点放在如何在Linux平台上开发OpenGL程序。介绍支持OpenGL的几个工具包,并辅以详细的实例来阐述。

1. Linux下OpenGL编程环境简介

OpenGL不是自由软件,它的版权、商标(OpenGL这个名字)都归SGI公司所有。但在Linux下有OpenGL的取代产品:Mesa。Mesa提供和OpenGL几乎完全一致的接口,对利用OpenGL API编程的人来说,几乎感觉不到任何差异。Mesa是遵循GPL协议(部分遵循LGPL协议)的自由软件,而且,正是由于Mesa的自由性,它在对新硬件的支持度等方面都超过了OpenGL。Mesa可以从www.mesa3d.org取得。得到Mesa后,依照说明即可生成编写程序所需要的动态、静态连接库和头文件。

了解OpenGL的读者都知道,OpenGL本身只提供三维图形接口,不具备绘制窗口、接受响应、处理消息等功能。这些功能必须由第三方的开发环境提供,如上面提及的VC等等。有人会想,既然在Motif下可以开发OpenGL程序,那么,使用Linux下的Lesstif也应该可以。是的,的确可以,但不幸的是,Linux下的Lesstif是一个很不成熟的产品,而且也不具有可移植性,所以应用Lesstif开发的人很少。下面我们简单介绍几个常用的工具包。

在Linux下开发OpenGL程序,最常用的工具是GLUT(The OpenGL Utility Toolkit)。它可以创建一个或多个OpenGL窗口,响应、处理用户的交互操作、简单的弹出式菜单以及一些内置的绘图和字体处理功能。GLUT和OpenGL一样,可以移植于多种平台。由于它良好的表现,现在它已经成为Mesa发布的标准套件之一。

另一个很好的开发工具包是FLTK(Fast Light Tool Kit),这是一个用C++编写的图形界面开发工具。和GTK++、KDE不同,它只关注于图形界面的设计,而尽量不牵涉其他的实际应用。这个特点使得它比其他许多开发工具简练和高效。而且,它同样也是一个具有良好移植性的开发工具。事实上,它现在正引来越来越多人的兴趣,许多商业软件(尤其是致力于开发嵌入式桌面系统的软件)都选用了它作为图形界面的开发工具。关于它的详细情况参见作者的另一篇文章《FLTK---一个优秀的图形界面开发工具包》。在FLTK里有一个组件:Fl_Gl_Window是专门的OpenGL窗口,利用它开发OpenGL程序相当方便。

最后要提的是GTK和KDE,它们是目前在Linux下用的最多的开发工具。GTK本身并不直接支持OpenGL(新的版本是否支持,尚不太清楚),但有人开发了支持OpenGL的Widget,叫做GLAREA,需要的读者可以到网上去查找或者与本文作者联系。KDE提供了对OpenGL的支持,但它的缺陷之一是KDE只运行于Linux系统,不具有可移植性。在这里,我将主要向大家介绍前面两个工具包。

2. 用GLUT开发OpenGL程序

2.1 如何获得

GLUT可以从Mesa中获得,读者也可以直接到它的主页去下载它:http://reality.sgi.com/employees/mjk_asd/glut3/glut3.html。按照说明安装后在OpenGL的头文件GL目录下将会有GLUT的头文件glut.h,同时安装的还有库文件libglut.a或libglut.so。有了它们以后,就可以用GLUT来编程了。

2.2 一个简单的例子

下面,我们先看一个简单的例子。这个例子画一个立体的球。

/* light.c

此程序利用GLUT绘制一个OpenGL窗口,并显示一个加以光照的球。

*/

/* 由于头文件glut.h中已经包含了头文件gl.h和glu.h,所以只需要include 此文件*/

# include < GL / glut.h >

# include < stdlib.h >

/* 初始化材料属性、光源属性、光照模型,打开深度缓冲区 */

void init ( void )

{

GLfloat mat_specular [ ] = { 1.0, 1.0, 1.0, 1.0 };

GLfloat mat_shininess [ ] = { 50.0 };

GLfloat light_position [ ] = { 1.0, 1.0, 1.0, 0.0 };

glClearColor ( 0.0, 0.0, 0.0, 0.0 );

glShadeModel ( GL_SMOOTH );

glMaterialfv ( GL_FRONT, GL_SPECULAR, mat_specular);

glMaterialfv ( GL_FRONT, GL_SHININESS, mat_shininess);

glLightfv ( GL_LIGHT0, GL_POSITION, light_position);

glEnable (GL_LIGHTING);

glEnable (GL_LIGHT0);

glEnable (GL_DEPTH_TEST);

}

/*调用GLUT函数,绘制一个球*/

void display ( void )

{

glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glutSolidSphere (1.0, 40, 50);

glFlush ();

}

/* 定义GLUT的reshape函数,w、h分别是当前窗口的宽和高*/

void reshape (int w, int h)

{

glViewport (0, 0, (GLsizei) w, (GLsizei) h);

glMatrixMode (GL_PROJECTION);

glLoadIdentity ( );

if (w <= h)

glOrtho (-1.5, 1.5, -1.5 * ( GLfloat ) h / ( GLfloat ) w,

1.5 * ( GLfloat ) h / ( GLfloat ) w, -10.0, 10.0 );

else

glOrtho (-1.5 * ( GLfloat ) w / ( GLfloat ) h,

1.5 * ( GLfloat ) w / ( GLfloat ) h, -1.5, 1.5, -10.0, 10.0);

glMatrixMode ( GL_MODELVIEW );

glLoadIdentity ( ) ;

}

/* 定义对键盘的响应函数 */

void keyboard ( unsigned char key, int x, int y)

{

/*按Esc键退出*/

switch (key) {

case 27:

exit ( 0 );

break;

}

}

int main(int argc, char** argv)

{

/* GLUT环境初始化*/

glutInit (&argc, argv);

/* 显示模式初始化 */

glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH);

/* 定义窗口大小 */

glutInitWindowSize (300, 300);

/* 定义窗口位置 */

glutInitWindowPosition (100, 100);

/* 显示窗口,窗口标题为执行函数名 */

glutCreateWindow ( argv [ 0 ] );

/* 调用OpenGL初始化函数 */

init ( );

/* 注册OpenGL绘图函数 */

glutDisplayFunc ( display );

/* 注册窗口大小改变时的响应函数 */

glutReshapeFunc ( reshape );

/* 注册键盘响应函数 */

glutKeyboardFunc ( keyboard );

/* 进入GLUT消息循环,开始执行程序 */

glutMainLoop( );

return 0;

}

从上面的例子中我们可以看出,GLUT采用一种函数注册的机制来实现OpenGL绘图。它的一般流程正如我们上面的注释所写,先是初始化函数,定义窗口,然后执行OpenGL初始化程序,这主要是一些需要全局设置的环境变量。接下来是注册相应事件的函数,包括完成实际绘图工作的绘制程序、改变OpenGL窗口大小时的响应函数、键盘事件的响应函数和鼠标时间的响应函数。最后调用glutMainLoop()函数,执行在glutReshapeFunc和glutDisplayFunc中注册的函数,进入消息循环。当用户通过键盘和鼠标进行交互操作时,它即调用相应的函数。

我们编译上面的名为light.c的源文件。假定头文件(目录GL)放在目录/usr/local/include下,库文件(动态库libGL.so.*、libGLU.so.*和libglut.so.*)在目录/usr/local/lib目录下,并已经运行了ldconfig,则编译命令为:

gcc -I/usr/local/include -L/usr/local/lib -L/usr/X11R6/lib -lglut -lGLU -lGL

-lX11 -lXext -lXmu -lXi -lm light.c -o light

其中的-lX11 -lXert -lXi -lm 是绘制窗口需要的X的库,它们默认在 /usr/X11R6/lib目录下。下面的图一即是运行light的结果,当按下ESC键时,程序会退出。调整窗口大小时,图形自动重绘。注意在上面reshape函数中,比较w和h的值给出的取景变换,这是一个常用的技巧。

.net/OS/linux/index7/file:///E/web/1.gif"

图一

2.3 GLUT简介

GLUT常用的函数主要包括以下几类:

· 初始化函数。主要就是上面例子中的几个函数。

· 消息循环函数。即glutMainLoop函数。

· 窗口管理函数。包括窗口的创建、修改、删除等。GLUT支持多个OpenGL窗口。

· Overlay管理函数。当用户显卡支持Overlay方式时,可以用这些函数来创建、管理、删除GLUT窗口的Overlay。

· 菜单管理函数。定制菜单以及定义菜单相应事件。

· 事件注册函数。除了上面例子中提及的外,还有鼠标、空间球(提供三维操作的装备)、特殊键(Ctrl、Shift、F系列键、方向键)等设备的事件注册函数。

· 字体绘制函数。用多种字体、字号供选择。

· 简单几何体的绘制程序。包括球、立方体、锥体、圆环体、十二面体、八面体、四面体、二十面体和茶壶。每种几何体都有实体和虚线两个选项。

· 取状态函数。类似OpenGL的glGet系列函数,取得GLUT的各种状态值。

· 颜色索引表函数。

这些函数极大的方便了用户的OpenGL编程。下面我们简略介绍一下几个常用的函数。

· glutPostRedisplay()。发送消息给函数glutMainLoop,请求重绘本窗口。利用此函数可以实现动画。例如在上面的例子中,我们添加一个全局变量:float move=0.0。并定义函数MoveSphere如下:

void MoveSphere ( void )

{

for(int i=0;i<100;i++){

if ( move<1.0) move+=0.1;

else move=0.0;

glutPostRedisplay ( );

}

}

同时修改函数display()为:

void display ( void )

{

glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glTranslatef ( move, 0.0, 0.0);

glutSolidSphere (1.0, 40, 50);

glFlush ();

}

这样,当我们执行函数MoveSphere时,就会看到上面的球从中间向右移动一段距离,然后又回到中心,继续移动。

· glutIdleFunc()函数。这个函数注册一个空闲程序一直在后台运行。我们将上面的MoveSphere函数加以修改,去掉循环,然后在light.c程序的glutMainLoop()函数调用前添加一行代码:glutIdleFunc (MoveSphere);这样我们不需要直接调用函数MoveSphere,程序一运行,它就被反复调用直到我们退出程序为止,这和我们前一版本中它只能循环特定的步数不一样。

· glutTimerFunc()函数。和前面的glutIdleFunc()函数类似,但不同的是它注册的函数每隔特定的事件发生。时间的单位是毫秒。

· glutBitmapCharacter()函数。用位图方式按指定的字体绘制一个字符串。

· glutSolidSphere()函数。这是绘制几何体类函数中的一个。此函数绘制一个球体。

2.4 一个更有代表性的例子

下面我们来看一个稍稍复杂的例子。我们绘制一个平面,用户的左键点击被自动连接成一个多边形。当用户点击右键,会弹出菜单供用户选择。用户可以选择清除、镶嵌和退出。选择清除将回到初始状态;选择镶嵌程序自动对多边形进行三角剖分;选择退出则终止程序。(见图二、图三和图四)

.net/OS/linux/index7/file:///E/web/2.gif"

.net/OS/linux/index7/file:///E/web/3.gif"图二
.net/OS/linux/index7/file:///E/web/4.gif"图三 图四

/* tessdemo.c 多边形镶嵌的例子,使用函数gluTessCallback和函数gluTessVertex。*/

#include

#include

#include

#include

/* 定义允许的最大多边形数、多边形允许的最大顶点数和可镶嵌的最大三角形数*/

#define MAX_POINTS 256

#define MAX_CONTOURS 32

#define MAX_TRIANGLES 256

/* 用于菜单选项的枚举类型 */

typedef enum{ QUIT, TESSELATE, CLEAR } menu_entries;

static mode_type mode;

/* 定义绘制模式的枚举类型 */

typedef enum{ DEFINE, TESSELATED } mode_type;

static int menu;

static GLsizei width, height; /* OpenGL窗口的大小 */

static GLuint contour_cnt; /* 记录多边形数目 */

static GLuint triangle_cnt; /* 记录三角形数目 */

static GLuint list_start; /* 用于显示列表 */

/* 多边形结构 */

static struct {

GLfloat p[MAX_POINTS][2];

GLuint point_cnt;

} contours [ MAX_CONTOURS ] ;

/* 三角形结构 */

static struct {

GLsizei no;

GLfloat p [3] [2];

GLclampf color [3] [3];

} triangles [ MAX_TRIANGLES ];

/* 窗口大小改变时,设定width和height值,用于重新绘制网格 */

void set_screen_wh ( GLsizei w, GLsizei h )

{ width = w; height = h; }

void tesse ( void )

{ /* 镶嵌函数,调用gluTess* 函数实现*/ }

/* 对点击鼠标左键事件的响应函数:更新当前多边形顶点数组,并重新绘制 */

void left_down ( int x1, int y1 )

{

GLfloat P[2];

GLuint point_cnt;

/* 将GLUT窗口坐标变换为GL坐标:前者(0,0)在左上角而后者在左下角*/

P[0] = x1; P[1] = height - y1;

/* 更新顶点数据 */

point_cnt = contours [ contour_cnt ] . point_cnt;

contours [ contour_cnt ] . p [ point_cnt ][ 0 ] = P [ 0 ];

contours [ contour_cnt ]. p [ point_cnt ] [ 1 ] = P [ 1 ];

/* 绘制新添加的边,若为第一个点,则绘制一个点 */

glBegin ( GL_LINES );

if ( point_cnt ) {

glVertex2fv ( contours[contour_cnt].p[point_cnt-1] );

glVertex2fv ( P );

}

else {

glVertex2fv ( P );

glVertex2fv ( P );

}

glEnd();

[1] [2] [3] 下一页

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有