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几乎完全一致的接口,对利用OpenGLAPI编程的人来说,几乎感觉不到任何差异。Mesa是遵循GPL协议(部分遵循LGPL协议)的自由软件,而且,正是由于Mesa的自由性,它在对新硬件的支持度等方面都超过了OpenGL。Mesa可以从www.mesa3d.org取得。得到Mesa后,依照说明即可生成编写程序所需要的动态、静态连接库和头文件。
了解OpenGL的读者都知道,OpenGL本身只提供三维图形接口,不具备绘制窗口、接受响应、处理消息等功能。这些功能必须由第三方的开发环境提供,如上面提及的VC等等。有人会想,既然在Motif下可以开发OpenGL程序,那么,使用Linux下的Le tif也应该可以。是的,的确可以,但不幸的是,Linux下的Le tif是一个很不成熟的产品,而且也不具有可移植性,所以应用Le tif开发的人很少。下面我们简单介绍几个常用的工具包。
在Linux下开发OpenGL程序,最常用的工具是GLUT(TheOpenGLUtility 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_ ecular [ ] = { 1.0, 1.0, 1.0, 1.0 };
GLfloat mat_shinine [ ] = { 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_ ECULAR, mat_ ecular);
glMaterialfv ( GL_FRONT, GL_SHININE , mat_shinine );
glLightfv ( GL_LIGHT0, GL_POSITION, light_position);
glEnable (GL_LIGHTING);
glEnable (GL_LIGHT0);
glEnable (GL_DEPTH_TEST);
}
/*调用GLUT函数,绘制一个球*/
void di lay ( void )
{
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glutSolid here (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 ( u igned char key, int x, int y)
{
/*按Esc键退出*/
switch (key) {
case 27:
exit ( 0 );
break;
}
}
int main(int argc, char** argv)
{
/*GLUT环境初始化*/
glutInit (&am argc, argv);
/* 显示模式初始化 */
glutInitDi layMode (GLUT_SINGLE |GLUT_RGB |GLUT_DEPTH);
/* 定义窗口大小 */
glutInitWindowSize (300, 300);
/* 定义窗口位置 */
glutInitWindowPosition (100, 100);
/* 显示窗口,窗口标题为执行函数名 */
glutCreateWindow ( argv [ 0 ] );
/* 调用OpenGL初始化函数 */
init ( );
/* 注册OpenGL绘图函数 */
glutDi layFunc ( di lay );
/* 注册窗口大小改变时的响应函数 */
glutReshapeFunc ( reshape );
/* 注册键盘响应函数 */
glutKeyboardFunc ( keyboard );
/* 进入GLUT消息循环,开始执行程序 */
glutMainLoop( );
return 0;
}
从上面的例子中我们可以看出,GLUT采用一种函数注册的机制来实现OpenGL绘图。它的一般流程正如我们上面的注释所写,先是初始化函数,定义窗口,然后执行OpenGL初始化程序,这主要是一些需要全局设置的环境变量。接下来是注册相应事件的函数,包括完成实际绘图工作的绘制程序、改变OpenGL窗口大小时的响应函数、键盘事件的响应函数和鼠标时间的响应函数。最后调用glutMainLoop()函数,执行在glutReshapeFunc和glutDi layFunc中注册的函数,进入消息循环。当用户通过键盘和鼠标进行交互操作时,它即调用相应的函数。
我们编译上面的名为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的值给出的取景变换,这是一个常用的技巧。