Linux 3D 编程学习总结

Linux下应用OGRE开发3D

linux下应用OGRE开发3D的资料网上很少,今天抽空整理一下。

大部分内容参考OGRE主页http://www.ogre3d.org/。

首先根据主页提示,我们可以利用已有资源构建一个工程,具体步骤如下:

第一步,准备工作,确定你是在linux环境下,进入终端,输入一下命令:

编译和配置

sudo apt-get install build-essential automake libtool

需要的依赖

sudo apt-get install libfreetype6-dev libfreeimage-dev libzzip-dev libxrandr-dev libxaw7-

dev freeglut3-dev

下面是可选项,一般还是装上比较稳妥,不然后面出现问题不易查找

sudo apt-get install nvidia-cg-toolkit libois-dev libboost-thread-dev

sudo apt-get install doxygen graphviz libcppunit-dev

至此我们的准备工作已完成。接下来就要下载工程源代码,然后编译。

第二步,下载并编译工程:

下载工程源码文件:http://www.ogre3d.org/download/source/OGRE 1.7.4 Source for Linux / OSX

解压文件到/home目录下:

tar xjf ogre_src_v1-7-4.tar.bz2

进入目录:

cd ogre_src_v1-7-4

新建文件build,这个文件时用来存放编译工程项目的,所有的编译内容都将放在此目录下:

mkdir build

进入此目录:

cd build

由于此OGRE工程采用的CMake工具链进行编译。所以使用CMake命令开始编译:

cmake ..

编译器会根据CMakeLists.txt产生一个新的CMakeFile文件,接下来的编译就和Make编译一样:

make -j2

如过此处显示拒绝情况可以加sudo:sudo make -j2

最后一步:

sudo make install

所有的编译工作已完成,下面就是执行工程,看看3D效果的,这里还是要说明一下,如果你的电脑不支

持3D那就郁闷吧,因为这直接影响3D的渲染,结果当然是没办法看到执行的结果。如果支持3D渲染就继

续一下操作吧!

cd build (这步已经执行了,只是告诉一下是在这个目录下)

cd bin

看到可执行文件了吧!

./Samplexxxxxxx  这个文件名记不全了,开头那几个字母的文件就这一个,执行后会弹出一个界面,然

后选择rendersystem,按住不放选中下来菜单,接下来就可以进入了,这里你会看到所有你编译的例子

,3D的,太棒了!如果愿意,你可以修改源文件参数,重新编译。

========

Android+Unity3D简单的物体运动

  我们来了解一下Translate的使用

  首先我们来看看场景的搭建:建一个立方体,加一个点光源。

  我们要实现的就是让场景中的立方体延X轴嗖嗖的移动

  那么我们在Project新建一个js脚本Creat->Javascript

  键入代码

  function Update ()

{

transform.Translate(Vector3(1,0,0));

}

  然后将js文件拖到Hierarchy面板的立方体上实现绑定。

  运行一下,我们可以看到,立方体嗖的一声不见了。它一定是肚子饿了赶去吃饭了。

  好了,我们来修改代码让它慢一点。

  function Update ()

{

transform.Translate(Vector3(1,0,0)*Time.deltaTime);

}

  运行一下,这会它老实了,慢慢的移动了。

  这是怎么回事呢。接下来我们一步一步的分解代码。

  首先Update()没什么好讲的了,一直在用,相信大家都明白怎么回事。

  接下来是

  transform:场景中的每一个对象都有一个transform,用来储存和控制物体的位置,旋转和缩放。

  Translate:是transform的函数,用来移动物体。它接受一个三维向量(Vector3)参数来移动。其

实它还有第二个参数,就是按照自身坐标轴移动还是按照世界坐标轴移动。这里暂且不表。

  Vector3:表示3D的向量和点。3个参数分别代表了向量x,y,z。

  transform.Translate(Vector3(1,0,0));这句代码的意思就是,让被绑定的物体,也就是场景中的

立方体,向x轴的方向移动1个单位.

  Time.deltaTime:是一个时间增量,我想应该是这一帧的时间。像flash中的一秒30帧,每帧多少秒

之类的。在这个程序中它的值是0.016左右。原本移动一个单位,现在乘以0.016,那肯定慢了。也就是

说,它的作用其实就是减慢移动的速度。

  OK。

  本文工程源码下载:

  免费下载地址在

  用户名与密码都是

  具体下载目录在 /pub/Android源码集锦/2011年/11月/Android+Unity3D简单的物体运动/

========

Linux下的OpenGL编程

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的值给出的取景变换,这是一个常用的技巧。

          图一

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 一个更有代表性的例子

   下面我们来看一个稍稍复杂的例子。我们绘制一个平面,用户的左键点击被自动连接成一个多边形

。当用户点击右键,会弹出菜单供用户选择。用户可以选择清除、镶嵌和退出。选择清除将回到初始状

态;选择镶嵌程序自动对多边形进行三角剖分;选择退出则终止程序。(见图二、图三和图四)

       图二                图三               图四

/* 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();

glFinish();

contours[contour_cnt].point_cnt++;

}

/* 点击鼠标中键的响应事件,有些系统可以用同时点击左右键模拟:结束一个多边形 */

void middle_down( int x1, int y1 )

{

GLuint point_cnt;

(void) x1;

(void) y1;

point_cnt = contours[contour_cnt].point_cnt;

/* 连接起始点和最后一个点,构成一个完整的多边形 */

if ( point_cnt > 2 )

{

glBegin( GL_LINES );

glVertex2fv( contours[contour_cnt].p[0] );

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

contours[contour_cnt].p[point_cnt][0] = -1;

glEnd();

glFinish();

contour_cnt++;

contours[contour_cnt].point_cnt = 0;

}

}

/* 处理鼠标响应的函数,根据按键的类型调用不同的函数:左键和中键。 */

void mouse_clicked( int button, int state, int x, int y )

{

/* 将OpenGL的像素坐标换为背景的网格坐标,背景网格为边长为10的小正方形 */

x -= x%10;

y -= y%10;

switch ( button ) {

case GLUT_LEFT_BUTTON: /* GLUT发现左键被点击 */

if ( state == GLUT_DOWN ) {

left_down( x, y );

}

break;

case GLUT_MIDDLE_BUTTON: /* 中键被点击 */

if ( state == GLUT_DOWN ) {

middle_down( x, y );

}

break;

}

}

/* OpenGL绘制函数,有两种模式 */

void display( void )

{

GLuint i,j;

GLuint point_cnt;

glClear( GL_COLOR_BUFFER_BIT );

switch ( mode )

{

case DEFINE: /* 多边形定义阶段 */

/* 绘制网格,单个网格大小为10像素,网格数目取决于OpenGL窗口大小 */

glColor3f ( 0.6, 0.5, 0.5 );

glBegin ( GL_LINES );

for ( i = 0 ; i < width ; i += 10 ){

for ( j = 0 ; j < height ; j += 10 ) {

glVertex2i ( 0, j );

glVertex2i ( width, j );

glVertex2i ( i, height );

glVertex2i ( i, 0 );

}

}

/* 绘制多边形 */

glColor3f( 1.0, 1.0, 0.0 );

for ( i = 0 ; i <= contour_cnt ; i++ ) {

point_cnt = contours[i].point_cnt;

glBegin( GL_LINES );

switch ( point_cnt ) {

case 0:

break;

case 1:

glVertex2fv ( contours[i].p[0] );

glVertex2fv ( contours[i].p[0] );

break;

case 2:

glVertex2fv( contours[i].p[0] );

glVertex2fv( contours[i].p[1] );

break;

default:

--point_cnt;

for ( j = 0 ; j < point_cnt ; j++ ) {

glVertex2fv ( contours [ i ]. p [ j ] );

glVertex2fv ( contours [ i ] .p [ j+1 ] );

}

if ( contours [ i ].p [ j+1 ] [ 0 ] == -1 )

{

glVertex2fv ( contours [ i ]. p [ 0 ] );

glVertex2fv ( contours [ i ] .p [ j ] );

}

break;

}

glEnd();

}

glFinish();

break;

case TESSELATED: /* 绘制镶嵌后的多边形,显示列表由函数tesse()给出 */

glColor3f( 0.7, 0.7, 0.0 );

glCallList( list_start );

glLineWidth( 2.0 );

glCallList( list_start + 1 );

glLineWidth( 1.0 );

glFlush();

break;

}

glColor3f( 1.0, 1.0, 0.0 );

}

/* 菜单选项clear的响应函数,将所有变量清零,绘制模式设为DEFINE */

void clear( void )

{

contour_cnt = 0;

contours[0].point_cnt = 0;

triangle_cnt = 0;

mode = DEFINE;

glDeleteLists( list_start, 2 );

list_start = 0;

}

/* 菜单选项quit的响应函数,退出程序 */

void quit( void )

{

exit( 0 );

}

/* 定义菜单的响应函数 */

void menu_selected( int entry )

{

switch ( entry ) {

case CLEAR:

clear ( );

break;

case TESSELATE:

tesse ( );

break;

case QUIT:

quit ( );

break;

}

/* 选择菜单后重绘OpenGL窗口 */

glutPostRedisplay();

}

/* 定义快捷键响应函数 */

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

{

/* 在此例子中,不需要用表明鼠标位置的变量x和y */

( void ) x; ( void ) y;

/* 针对不同按键,定义动作 */

switch ( key ) {

case ‘c‘:

case ‘C‘:

clear();

break;

case ‘t‘:

case ‘T‘:

tesse();

break;

case ‘q‘:

case ‘Q‘:

quit();

break;

}

/* 按键后重绘窗口 */

glutPostRedisplay();

}

/* 执行一些程序的初始化过程 */

void myinit( void )

{

/* 设置窗口背景颜色*/

glClearColor( 0.4, 0.4, 0.4, 0.0 );

glShadeModel( GL_FLAT );

glPolygonMode( GL_FRONT, GL_FILL );

/* 创建一个菜单,并定义菜单项及该菜单对应的响应函数 */

menu = glutCreateMenu( menu_selected );

glutAddMenuEntry( "clear", CLEAR );

glutAddMenuEntry( "tesselate", TESSELATE );

glutAddMenuEntry( "quit", QUIT );

/* 定义菜单动作方式:点击右键弹出 */

glutAttachMenu( GLUT_RIGHT_BUTTON );

/* 注册鼠标事件响应函数 */

glutMouseFunc( mouse_clicked );

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

glutKeyboardFunc( key_pressed );

contour_cnt = 0;

mode = DEFINE;

}

/* 定义窗口大小改变时的响应 */

static void reshape( GLsizei w, GLsizei h )

{

glViewport( 0, 0, w, h );

glMatrixMode( GL_PROJECTION );

glLoadIdentity();

glOrtho( 0.0, (GLdouble)w, 0.0, (GLdouble)h, -1.0, 1.0 );

glMatrixMode( GL_MODELVIEW );

glLoadIdentity();

set_screen_wh( w, h );

}

int main( int argc, char **argv )

{

/* 创建窗口 */

glutInit ( & argc, argv );

glutInitDisplayMode ( GLUT_SINGLE | GLUT_RGB );

glutInitWindowSize ( 400, 400 );

glutCreateWindow( argv[0] );

myinit();

glutDisplayFunc( display );

glutReshapeFunc( reshape );

glutMainLoop();

return 0;

}

3. 用FLTK开发OpenGL程序

   从上面的例子我们不难看出,虽然GLUT为实现OpenGL编程提供了可能,但是作为应用程序,它是远

远不够的。它只提供了原始、简陋的控制和操作方式,没有一般应用程序所需要的按钮、菜单条、输入

框等控件。事实上,GLUT并不是用来单独开发应用程序的,它是用作介于OpenGL函数接口和一般的图形

界面开发接口之间的过渡层。在这一点上,它无疑是成功的。Mesa选择它作为标准套件分发,大多数图

形界面开发工具也保持与它的兼容性。从而使得用GLUT开发的OpenGL程序有良好的可移植性。

   和GLUT不同,FLTK本身是一个图形界面开发工具,使用它完全可以开发实用的、商用的应用程序。

FLTK用C++编写,使用面向对象的开发技术,它提供多种组件供用户选用,每个组件有自己的属性和事件

。在这里,我们主要讲述它的OpenGL窗口组件:Fl_Gl_Window,并充分使用C++的特性。

   这一节里,我们绘制一个可以自由旋转、平移、放缩的小立方体。程序运行后如图五所示。整个窗

口是一个由Fl_Window组件定义的一般窗口,中间是一个OpenGL窗口。我们使用了一些控制工具来调整小

立方体的属性。上面的Zoom标尺调整它的大小,左边和下边各有一个平移标尺和一个旋转标尺,调整小

立方体的位置和角度。这些标尺都是FLTK的标准组件,它们的作用是根据用户的动作返回特定的整数或

符点数。

   Fl_Gl_Window最重要的是两个虚函数:draw()、handle()和成员函数redraw()。函数draw(

)中定义绘制内容,创建窗口和窗口大小改变是这个函数被自动调用。函数handle()中定义对各种键

盘、鼠标事件的响应。当有键盘、鼠标事件响应时,这个函数被自动调用,如何有响应事件的函数被定

义,则会执行此函数。函数redraw()重绘窗口。在这个叫做CubeView的例子中,我们派生

Fl_Gl_Window,得到绘制我们这个小立方体的OpenGL窗口。

// 文件CubeView.cxx,派生Fl_Gl_Window,得到绘制小立方体的OpenGL窗口

#include

#include

#include

#include

#include

// 派生类CubeView的定义

class CubeView : public Fl_Gl_Window {

public:

double size; // 定义小立方体的大小,供glScalef()函数使用

// 构造函数,派生自Fl_Gl_Window,定义窗口大小和标题

CubeView(int x,int y,int w,int h,const char *l=0);

// 设置和取得垂直方向的旋转角度,供组件标尺调用

void v_angle(float angle){vAng=angle;};

float v_angle(){return vAng;};

// 设置和取得水平方向的旋转角度,供组件标尺调用

void h_angle(float angle){hAng=angle;};

float h_angle(){return hAng;};

// 设置水平和垂直方向的偏移量

void panx(float x){xshift=x;};

void pany(float y){yshift=y;};

void draw();

private:

void drawCube();

float vAng,hAng;

float xshift,yshift;

float boxv0[3];float boxv1[3];

float boxv2[3];float boxv3[3];

float boxv4[3];float boxv5[3];

float boxv6[3];float boxv7[3];

};

// 构造函数的定义

CubeView::CubeView(int x,int y,int w,int h,const char *l)

: Fl_Gl_Window(x,y,w,h,l)

{

// 设置变换初值

vAng = 0.0;

hAng=0.0;

size=10.0;

// 设置小立方体顶点参数

boxv0[0] = -0.5; boxv0[1] = -0.5; boxv0[2] = -0.5;

boxv1[0] = 0.5; boxv1[1] = -0.5; boxv1[2] = -0.5;

boxv2[0] = 0.5; boxv2[1] = 0.5; boxv2[2] = -0.5;

boxv3[0] = -0.5; boxv3[1] = 0.5; boxv3[2] = -0.5;

boxv4[0] = -0.5; boxv4[1] = -0.5; boxv4[2] = 0.5;

boxv5[0] = 0.5; boxv5[1] = -0.5; boxv5[2] = 0.5;

boxv6[0] = 0.5; boxv6[1] = 0.5; boxv6[2] = 0.5;

boxv7[0] = -0.5; boxv7[1] = 0.5; boxv7[2] = 0.5;

};

void CubeView::drawCube() {

// 绘制一个半透明的立方体

#define ALPHA 0.5

glShadeModel(GL_FLAT);

// 用不同的颜色绘制六个面

glBegin(GL_QUADS);

glColor4f (0.0, 0.0, 1.0, ALPHA );

glVertex3fv ( boxv0 ); glVertex3fv ( boxv1 ); glVertex3fv ( boxv2 ); glVertex3fv( boxv3 );

glColor4f(1.0, 1.0, 0.0, ALPHA);

glVertex3fv ( boxv0 ); glVertex3fv ( boxv4 ); glVertex3fv ( boxv5 ); glVertex3fv ( boxv1 );

glColor4f(0.0, 1.0, 1.0, ALPHA);

glVertex3fv ( boxv2 ); glVertex3fv ( boxv6 ); glVertex3fv ( boxv7 ); glVertex3fv ( boxv3 );

glColor4f(1.0, 0.0, 0.0, ALPHA);

glVertex3fv ( boxv4 ); glVertex3fv ( boxv5 ); glVertex3fv ( boxv6 ); glVertex3fv ( boxv7 );

glColor4f(1.0, 0.0, 1.0, ALPHA);

glVertex3fv ( boxv0 ); glVertex3fv ( boxv3 ); glVertex3fv ( boxv7 ); glVertex3fv ( boxv4 );

glColor4f(0.0, 1.0, 0.0, ALPHA);

glVertex3fv ( boxv1 ); glVertex3fv ( boxv5 ); glVertex3fv ( boxv6 ); glVertex3fv ( boxv2 );

glEnd();

// 绘制立方体的轮廓线,一共12条

glColor3f(1.0, 1.0, 1.0);

glBegin(GL_LINES);

glVertex3fv ( boxv0 ); glVertex3fv ( boxv1 );

glVertex3fv ( boxv1 ); glVertex3fv ( boxv2 );

glVertex3fv ( boxv2 ); glVertex3fv ( boxv3 );

glVertex3fv ( boxv3 ); glVertex3fv ( boxv0 );

glVertex3fv ( boxv4 ); glVertex3fv ( boxv5 );

glVertex3fv ( boxv5 ); glVertex3fv ( boxv6 );

glVertex3fv ( boxv6 ); glVertex3fv ( boxv7 );

glVertex3fv ( boxv7 ); glVertex3fv ( boxv4 );

glVertex3fv ( boxv0 ); glVertex3fv ( boxv4 );

glVertex3fv ( boxv1 ); glVertex3fv ( boxv5 );

glVertex3fv ( boxv2 ); glVertex3fv ( boxv6 );

glVertex3fv ( boxv3 ); glVertex3fv ( boxv7 );

glEnd();

};

void CubeView::draw() {

if (!valid ( ) ) {

//valid()当窗口大小改变时改变,导致这一部分内容被执行,重新设置窗口

glLoadIdentity();

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

glOrtho(-10,10,-10,10,-20000,10000);

glEnable(GL_BLEND);

glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

}

glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

glPushMatrix ( );

// 变换。参数绘被外部函数修改

glTranslatef ( xshift, yshift, 0);

glRotatef ( hAng, 0, 1, 0 ); glRotatef ( vAng, 1, 0, 0 );

glScalef ( float ( size ), float ( size ) , float ( size ) );

// 绘制立方体

drawCube ( );

glPopMatrix ( );

};

上面的类CubeView定义了一个绘制立方体的OpenGL窗口,外部函数可以调用它的成员函数v_angle、

h_angle、panx、pany等来修改这个小立方体的属性,修改以后,可以调用函数redraw()来刷新窗口。

在下面的CubeViewUI.cxx中,我们定义类CubeViewUI,它绘制主窗口,并在其中定义了类CubeView的一

个实例:cube。它同时还定义了用来控制立方体属性的5个标尺,当用户操作标尺时,这些标尺调用

v_angle等函数来设置绘制立方体的一些参数。这一部分和我们的主题关系不大,不给出具体的代码。最

后,我们定义main函数,它的内容相当的简单。

#include "CubeViewUI.h"

int main(int argc, char **argv) {

// 定义类CubeViewUI的一个实例

CubeViewUI *cvui=new CubeViewUI;

// 设置FLTK窗口显示模式

Fl::visual(FL_DOUBLE|FL_INDEX);

cvui->show();

// 进入消息循环

return Fl::run();

}

我们编译、连接并执行程序,就可以得到如图五所示的结果。从上面的例子我们可以看出使用FLTK编写

OpenGL程序的一些优点,和GLUT它结构清晰,使用方便,而且它和GLUT是兼容的。除了glutInit()、

glutMainLoop()等少数函数外,大部分GLUT函数可以在FLTK中使用。FLTK本身也提供了许多OpenGL函

数,如绘制字符串的gl_draw()等。

4. 结束语

   熟悉掌握了Linux下OpenGL的开发环境距离开发OpenGL程序还有很大的距离,毕竟问题的难点是如

何很好的使用OpenGL的API。本文为即将在Linux下开发OpenGL的读者作一些铺垫和准备工作,希望并相

信对大家有所帮助。

========

linux openGL "Hello world"

1. 安装OpenGL相关工具

  sudo apt-get install mesa-common-dev libgl1-mesa-dev libglu1-mesa-dev freeglut3-dev

note:

libgl1-mesa-de 对应 GL库;

libglu1-mesa-dev对应GLU库 TJe opengl utility  library;

freeglut3-dev 对应glut库

mesa-common-de :This package includes the specifications for the Mesa-specific

OpenGL extensions, the complete set of release release notes and the development header

files common to all Mesa packages.

2. example 上代码:

#include <GL/glut.h>

#define window_width 640

#define window_height 480

// Main loop

void main_loop_function()

{

// Z angle

static float angle;

// Clear color (screen)

// And depth (used internally to block obstructed objects)

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

// Load identity matrix

glLoadIdentity();

// Multiply in translation matrix

glTranslatef(0, 0, -10);

// Multiply in rotation matrix

glRotatef(angle, 0, 0, 1);

// Render colored quad

glBegin(GL_QUADS);

glColor3ub(255, 000, 000);

glVertex2f(-1, 1);

glColor3ub(000, 255, 000);

glVertex2f(1, 1);

glColor3ub(000, 000, 255);

glVertex2f(1, -1);

glColor3ub(255, 255, 000);

glVertex2f(-1, -1);

glEnd();

// Swap buffers (color buffers, makes previous render visible)

glutSwapBuffers();

// Increase angle to rotate

angle += 0.25;

}

// Initialze OpenGL perspective matrix

void GL_Setup(int width, int height)

{

glViewport(0, 0, width, height);

glMatrixMode(GL_PROJECTION);

glEnable(GL_DEPTH_TEST);

gluPerspective(45, (float) width / height, .1, 100);

glMatrixMode(GL_MODELVIEW);

}

// Initialize GLUT and start main loop

int main(int argc, char** argv)

{

glutInit(&argc, argv);

glutInitWindowSize(window_width, window_height);

glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);

glutCreateWindow("GLUT Example!!!");

glutIdleFunc(main_loop_function);

GL_Setup(window_width, window_height);

glutMainLoop();

return 0;

}

3. 编译:

gcc example.cpp -o example -lglut -lGL -lGLU

4. 运行:

./example

========

linux下基于eclipse的opengl开发环境搭建

博客分类: opengl

eclipseopenglubuntu

转自:http://www.cnblogs.com/lycheng/archive/2011/09/13/2174831.html

1. 安装OpenGL相关工具

  sudo apt-get install mesa-common-dev libgl1-mesa-dev libglu1-mesa-dev freeglut3-dev

其中,

libgl1-mesa-de 对应 GL库;

libglu1-mesa-dev对应GLU库 TJe opengl utility  library;

freeglut3-dev 对应glut库

mesa-common-de :This package includes the specifications for the Mesa-specific

OpenGL extensions, the complete set of release release notes and the development header

files common to all Mesa packages.

2. 设置Eclipse

安装eclipse   cdt插件

8.0.0 下载地址: http://www.eclipse.org/cdt/downloads.php

  Project -> properties -> C / C++ Build / Settings -> Tool Setting

  然后选择Cross G++ Linker 选择 Libraries, 在Libraries 中插入: glut GL GLU

                      在Libraries Search Paths 中插入:

/usr/include/GL

3. 测试代码 example.cpp

Java代码  收藏代码

#include <GL/glut.h>

#define window_width 640

#define window_height 480

// Main loop

void main_loop_function()

{

// Z angle

static float angle;

// Clear color (screen)

// And depth (used internally to block obstructed objects)

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

// Load identity matrix

glLoadIdentity();

// Multiply in translation matrix

glTranslatef(0, 0, -10);

// Multiply in rotation matrix

glRotatef(angle, 0, 0, 1);

// Render colored quad

glBegin(GL_QUADS);

glColor3ub(255, 000, 000);

glVertex2f(-1, 1);

glColor3ub(000, 255, 000);

glVertex2f(1, 1);

glColor3ub(000, 000, 255);

glVertex2f(1, -1);

glColor3ub(255, 255, 000);

glVertex2f(-1, -1);

glEnd();

// Swap buffers (color buffers, makes previous render visible)

glutSwapBuffers();

// Increase angle to rotate

angle += 0.25;

}

// Initialze OpenGL perspective matrix

void GL_Setup(int width, int height)

{

glViewport(0, 0, width, height);

glMatrixMode(GL_PROJECTION);

glEnable(GL_DEPTH_TEST);

gluPerspective(45, (float) width / height, .1, 100);

glMatrixMode(GL_MODELVIEW);

}

// Initialize GLUT and start main loop

int main(int argc, char** argv)

{

glutInit(&argc, argv);

glutInitWindowSize(window_width, window_height);

glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);

glutCreateWindow("GLUT Example!!!");

glutIdleFunc(main_loop_function);

GL_Setup(window_width, window_height);

glutMainLoop();

return 0;

}

  Run All 之后, 会显示旋转的方型, 如果不需要IDE, 则可用命令行编译。

4. 命令行编译

  gcc example.cpp -o example -lglut -lGL -lGLU

  -o 表示输出的文件名

  -l 表示链接的库

========

时间: 2024-10-07 05:29:03

Linux 3D 编程学习总结的相关文章

linux网络编程学习笔记之二 -----错误异常处理和各种碎碎(更新中)

errno 在unix系统中对大部分系统调用非正常返回时,通常返回值为-1,并设置全局变量errno(errno.h),如socket(), bind(), accept(), listen().erron存放一个正整数来保存上次出错的错误值. 对线程而言,每个线程都有专用的errno变量,不必考虑同步问题. strerror converts to English (Note: use strerror_r for thread safety) perror is simplified str

linux网络编程学习笔记之六 -----I/O多路复用服务端

多进程和多线程的目的是在于最大限度地利用CPU资源,当某个进程不需要占用太多CPU资源,而是需要I/O资源时,可以采用I/O多路复用,基本思路是让内核把进程挂起,直到有I/O事件发生时,再把控制返回给程序.这种事件驱动模型的高效之处在于,省去了进程和线程上下文切换的开销.整个程序运行在单一的进程上下文中,所有的逻辑流共享整个进程的地址空间.缺点是,编码复杂,而且随着每个逻辑流并发粒度的减小,编码复杂度会继续上升. I/O多路复用典型应用场合(摘自UNP6.1) select的模型就是这样一个实现

Linux C编程学习5---参考《那年,一步一步学linux c》全系列(目录索引)

漫无目的的搜索一些东西,发现的一个很好的资源,所以就一定要收藏下来,方便自己学习Linux C 的时候也能够去参考一下别人的学习之路,来更加促进我的学习和思考 说明 转载请注明出处:谢谢:http://blog.csdn.net/muge0913/article/details/7342977 博主的邮箱是:[email protected] 文章中若有不对或某些功能更好的实现方法,请指出或直接留言. 该系列文章中所用结构数据代码均来自linux2.6.39. 1.那年,一步一步学linux c

linux网络编程学习笔记之五 -----并发机制与线程?

进程线程分配方式 简述下常见的进程和线程分配方式:(好吧,我仅仅是举几个样例作为笔记...并发的水太深了,不敢妄谈...) 1.进程线程预分配 简言之,当I/O开销大于计算开销且并发量较大时,为了节省每次都要创建和销毁进程和线程的开销.能够在请求到达前预先进行分配. 2.进程线程延迟分配 预分配节省了处理时的负担,但操作系统管理这些进程线程也会带来一定的开销.由此,有个折中的方法是,当某个处理须要花费较长时间的时候,我们创建一个并发的进程或线程来处理该请求.实现也非常easy,在主线程中定时,定

Linux C编程学习2---GCC编译器

GCC简介 GCC(GNU Compiler Collection)是一套功能强大.性能优越的编程语言编译器,它是GNU计划的代表作品之一.GCC以GPL和LGPL许可证发行,它是类Unix和苹果电脑 Mac OS X操作系统的标准编译器 除了支持C,还支持C++.Java GCC常用选项 1. 基本选项 类型 说明 -E 预处理后即停止,不进行编译.汇编及连接 -S 编译后即停止,不进行汇编及连接 -c 编译或汇编源文件,但是不进行连接 -o file 指定输出文件为 file 例子: gcc

linux网络编程学习笔记之四 -----多线程并发服务端

相对于使用进程实现并发,用线程的实现更加轻量.每个线程都是独立的逻辑流.线程是CPU上独立调度运行的最小单位,而进程是资源分配的单位.当然这是在微内核的操作系统上说的,简言之这种操作系统的内核是只提供最基本的OS服务,更多参看点击打开链接 每个线程有它自己的线程上下文,包括一个唯一的线程ID(linux上实现为unsigned long),栈,栈指针,程序计数器.通用目的寄存器和条件码,还有自己的信号掩码和优先级.同一个进程里的线程共享这个进程的整个虚拟地址空间,包括可执行的程序文本.程序的全局

linux网络编程学习笔记之五 -----并发机制与线程池

进程线程分配方式 简述下常见的进程和线程分配方式:(好吧,我只是举几个例子作为笔记...并发的水太深了,不敢妄谈...) 1.进程线程预分配 简言之,当I/O开销大于计算开销且并发量较大时,为了节省每次都要创建和销毁进程和线程的开销.可以在请求到达前预先进行分配. 2.进程线程延迟分配 预分配节省了处理时的负担,但操作系统管理这些进程线程也会带来一定的开销.由此,有个折中的方法是,当某个处理需要花费较长时间的时候,我们创建一个并发的进程或线程来处理该请求.实现也很简单,在主线程中定时,定时到期,

Linux下编程学习一

本篇主要记录一些在学习LINUX下编程时,, C和C++语言的一些基础的常识, 一. 函数指针 void MyFun(int x); 函数声明 void (*FunP)(int ); 函数指针声明 下面是C和C++中的指针定义  int (*pt2Function)(float, char, char) = NULL; // C普通函数指针 int (TMyClass::*pt2Member)(float, char, char) = NULL; // C++中指向静态函数的指针 int (TM

Linux C编程学习

C语言简介 简介 C语言具有控制特性较强.高效性.可移植性和强大的功能和灵活性."自由的代价是永远的警惕",C的简洁性与其丰富的运算符相结合,使其可能会编写出较难理解的代码.面向对象编程是一种哲学思想,它试图让语言来适应问题,而不是让问题适应语言.C是一种面向过程或者面向函数的编程,而c++是面向对象编程的一门C的超集. C语言运行机制 C语言编程的基本策略是使用程序将源代码转换为可执行文件,此文件包含可以运行的机器语言代码.C实现这个目标主要通过两个步骤实现:编译和链接.编译器将源代