10
3 OpenGL OpenGL Open Graphics Library)是一个工业标准的三维(包括二维)计算机图形 软件接口,由 SGI 公司发布并广泛应用于 UNIXOS/2Windows NTLinux 等多种平 台。在 Windows NT 平台上,一般的开发工具如 Visual C++Borland CVisual BasicDelphiFORTRAN 等都支持 OpenGL 应用的开发。多种 Java 开发软件也支持 OpenGL通用的编程语言或软件,如 Visual C++Java 等,不可能提供更多的图形绘制函数, 所以在实现一些具体的图形设计、动画游戏制作时,需要在 Visual C++Java 等平台下, 使用 OpenGL 等专用绘图函数及语言。很多动画与游戏出自于语言编程,其中很大一部 分是使用了 OpenGLOpenGL 是一些画图函数及其辅助函数的集合,使用(调用)这些函数可以方便图 形绘制,特别是三维图形及动画的制作。 3.1 Visual C++ Source File 运行 OpenGL 程序 3.1.1 Visual C++ 中的 OpenGL 头文件 为了方便使用,在 Visual C++6.0 中已经把 OpenGL 的一些重要的文件放入到平台中, 其中,程序可以调用的头文件 gl.hglu.h glaux.h 就放置在安装目录中的 Include 目录 GL 子目录下。使用 Visual C++6.0 默认提供的 OpenGL 功能就可以方便地绘制各种图 形以及制作动画。 【例 3-1使用 Visual C++6.0 (默认)提供的 OpenGL 功能绘制一个具有真实感的球。 执行 FileNew 命令,在建立项目对话框中,选择 Files 项,再选择 C++ Source File 选项,给文件命名,建立一个 C++ Source File在该文件中写入下面代码: #pragma comment( lib, "opengl32.lib") #pragma comment( lib, "glu32.lib") #pragma comment( lib, "glaux.lib") #include <windows.h> #include <GL\gl.h> #include <GL\glu.h>

3 OpenGL计算机图形学与动画技术86 编译运行,绘制的具有真实感的球,如图3-1(a)所示。 OpenGL 函数主要包含在两个通常叫做gl 与glu 的库中,前者称为核心库;后者称

  • Upload
    others

  • View
    14

  • Download
    0

Embed Size (px)

Citation preview

Page 1: 3 OpenGL计算机图形学与动画技术86 编译运行,绘制的具有真实感的球,如图3-1(a)所示。 OpenGL 函数主要包含在两个通常叫做gl 与glu 的库中,前者称为核心库;后者称

3 OpenGL

OpenGL(Open Graphics Library)是一个工业标准的三维(包括二维)计算机图形

软件接口,由 SGI公司发布并广泛应用于 UNIX、OS/2、Windows NT、Linux等多种平

台。在Windows NT平台上,一般的开发工具如 Visual C++、Borland C、Visual Basic、

Delphi、FORTRAN等都支持 OpenGL应用的开发。多种 Java开发软件也支持 OpenGL。

通用的编程语言或软件,如 Visual C++与 Java等,不可能提供更多的图形绘制函数,

所以在实现一些具体的图形设计、动画游戏制作时,需要在 Visual C++与 Java等平台下,

使用 OpenGL 等专用绘图函数及语言。很多动画与游戏出自于语言编程,其中很大一部

分是使用了 OpenGL。

OpenGL 是一些画图函数及其辅助函数的集合,使用(调用)这些函数可以方便图

形绘制,特别是三维图形及动画的制作。

3.1 Visual C++ Source File 运行 OpenGL 程序

3.1.1 Visual C++ 中的 OpenGL 头文件

为了方便使用,在Visual C++6.0中已经把OpenGL的一些重要的文件放入到平台中,

其中,程序可以调用的头文件 gl.h、glu.h与 glaux.h就放置在安装目录中的 Include目录

的 GL子目录下。使用 Visual C++6.0默认提供的 OpenGL功能就可以方便地绘制各种图

形以及制作动画。

【例 3-1】 使用 Visual C++6.0(默认)提供的 OpenGL功能绘制一个具有真实感的球。

执行 File→New命令,在建立项目对话框中,选择 Files项,再选择 C++ Source File

选项,给文件命名,建立一个 C++ Source File。

在该文件中写入下面代码:

#pragma comment( lib, "opengl32.lib")

#pragma comment( lib, "glu32.lib")

#pragma comment( lib, "glaux.lib")

#include <windows.h>

#include <GL\gl.h>

#include <GL\glu.h>

Page 2: 3 OpenGL计算机图形学与动画技术86 编译运行,绘制的具有真实感的球,如图3-1(a)所示。 OpenGL 函数主要包含在两个通常叫做gl 与glu 的库中,前者称为核心库;后者称

第 3章 OpenGL

85

#include <GL\glaux.h>

void myinit(void)

{

GLfloat mat_specular[]={1.0,1.0,1.0,1.0}; //定义 GL数组

GLfloat mat_shininess[]={50.0};

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

glMaterialfv(GL_FRONT,GL_SPECULAR,mat_specular);

//设置材料镜面光反射色

glMaterialfv(GL_FRONT,GL_SHININESS,mat_shininess); //设置材料反射指数

glLightfv(GL_LIGHT0,GL_POSITION,mat_position); //设置光源位置

glEnable(GL_LIGHTING);

glEnable(GL_LIGHT0);

glDepthFunc(GL_LEQUAL);

glEnable(GL_DEPTH_TEST);

}

void CALLBACK display(void)

{

glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);

auxSolidSphere(1.0); //绘制一个实心球

glFlush();

}

void CALLBACK myReshape(GLsizei w,GLsizei h)

{

glViewport(0,0,w,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);

}

glMatrixMode(GL_MODELVIEW);

glLoadIdentity();

}

int main(int argc,char** argv)

{

auxInitDisplayMode(AUX_SINGLE|AUX_RGBA|AUX_DEPTH);

auxInitPosition(0,0,500,500);

auxInitWindow(argv[0]);

myinit();

auxReshapeFunc(myReshape);

auxMainLoop(display);

return(true);

}

Page 3: 3 OpenGL计算机图形学与动画技术86 编译运行,绘制的具有真实感的球,如图3-1(a)所示。 OpenGL 函数主要包含在两个通常叫做gl 与glu 的库中,前者称为核心库;后者称

计算机图形学与动画技术

86

编译运行,绘制的具有真实感的球,如图 3-1(a)所示。

OpenGL 函数主要包含在两个通常叫做 gl 与 glu 的库中,前者称为核心库;后者称

为实用库。以 aux为前缀的函数属于辅助函数。例 3-1程序引入了相关的 3个头文件。

【思考题】 同样是绘制一个具有真实感的球,该程序与例1-7中的程序有什么不同?

把例 3-1程序中的语句

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

auxSolidShere(1.9);

auxInitPosition(0,0,500,500);

分别修改为

GLfloat mat_specular[]={0.5,0.2,0.6,0.0};

auxSolidTeapot(0.9);

auxInitPosition(0,0,500,400);

再编译运行程序,绘制如图 3-1(b)所示图形。

图 3-1 使用 OpenGL 接口函数绘制的一个具有真实感的球和茶壶

例 3-1 程序展示如何使用 OpenGL 绘图,学习一个新知识自然有一些困难,可以暂

时回避一些难点,学习下面内容,等学习本章其他内容后,回过来继续研究这个程序。

例 3-1 程序里面包含了许多陌生的代码,不易理解,写起来也比较烦琐。如果使用

glut(OpenGL Utility Toolkit),程序会短一些。glut文件需要到网上下载,作者下载了一

个,其包括的文件如图 3-2所示。

图 3-2 下载的 glut 文件包中含有的文件

把连接文件、头文件、库文件分别放在相应的目录下,如图 3-3所示。

图 3-3 把各个文件放到相应的文件夹中

Page 4: 3 OpenGL计算机图形学与动画技术86 编译运行,绘制的具有真实感的球,如图3-1(a)所示。 OpenGL 函数主要包含在两个通常叫做gl 与glu 的库中,前者称为核心库;后者称

第 3章 OpenGL

87

【例 3-2】 使用 glut库函数绘制一个真实感的球。

# include < GL/glut.h >

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

void init(void)

{

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

glClearColor ( 0.0, 0.0, 1.0, 0.0 ); //设置背景色为蓝色

glShadeModel ( GL_SMOOTH );

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); //半径为 1,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 ( ) ;

}

int main(int argc, char** argv)

{

glutInit (&argc, argv); // GLUT环境初始化

glutInitDisplayMode (GLUT_SINGLE |GLUT_RGB |GLUT_DEPTH);

// 显示模式初始化

glutInitWindowSize (300, 300); // 定义窗口大小

glutInitWindowPosition (100, 100); // 定义窗口位置

glutCreateWindow ( argv [ 0 ] ); // 显示窗口,窗口标题为执行函数名

init( ); // 调用 init函数

Page 5: 3 OpenGL计算机图形学与动画技术86 编译运行,绘制的具有真实感的球,如图3-1(a)所示。 OpenGL 函数主要包含在两个通常叫做gl 与glu 的库中,前者称为核心库;后者称

计算机图形学与动画技术

88

glutDisplayFunc ( display );

// 注册 OpenGL绘图函数(一种特殊的调用方式,下同)

glutReshapeFunc ( reshape ); // 注册窗口大小改变时的响应函数

glutMainLoop( ); // 进入 GLUT消息循环,开始执行程序

return 0;

}

运行结果如图 3-4(a)所示。

图 3-4 使用 glut 函数绘制的真实感图形

把语句 glutSolidSphere (1.0, 40, 50)修改为下面语句,绘制如图 3-4(b)~图 3-4(d)所

示的图。

glutSolidTeapot (0.9); //绘制一个茶壶,尺寸为 0.9

glutSolidTorus (0.5,0.8,20,30);

//绘制内径 0.5、外径 0.8的环面,后两个参数为分片数

glutSolidOctahedron(); //绘制一个实心的 8个面的正多面体

对例 3-1 与例 3-2 两个程序进行对比分析,可以发现主要区别在于辅助绘图的一些

函数上,gl与 glu为前缀的函数是一样的。

在本章后面的各节中,多使用 glut函数辅助绘图。

3.1.2 OpenGL 基本二维图形单元绘制

多边形是计算机图形学中最重要的图形单元,计算机上的图形多是由众多的多边形

构成的,所以首先在例 3-3中学习使用 OpenGL绘制多边形。

【例 3-3】 绘制多边形。

建立一个 C++ Source File,在其中设计下面程序:

#include <GL/glut.h>

void display()

{

glClear(GL_COLOR_BUFFER_BIT);

glBegin(GL_POLYGON);

glVertex2f(-0.5,-0.3);

glVertex2f(-0.3,0.3);

glVertex2f(0.3,0.3);

glVertex2f(0.8,-0.3);

glEnd();

glFlush();

Page 6: 3 OpenGL计算机图形学与动画技术86 编译运行,绘制的具有真实感的球,如图3-1(a)所示。 OpenGL 函数主要包含在两个通常叫做gl 与glu 的库中,前者称为核心库;后者称

第 3章 OpenGL

89

}

int main(int argc,char** argv)

{

glutInit(&argc,argv);

glutCreateWindow("simple");

glClearColor(1.0,1.0,1.0,0.8);

glColor3f(0.0,0.0,1.0);

glutDisplayFunc(display);

glutMainLoop();

}

编译运行,绘制的图形如图 3-5(a)所示。

如果在语句 glVertex2f(0.8, −0.3)的下面加入语句 glVertex2f(0.2, −0.8),即增加一

个顶点,绘制的图形如图 3-5(b)所示。

如果加入的语句改为 glVertex2f(0.2,0.6),绘制的结果如图 3-5(c)所示。

图 3-5 使用 OpenGL 函数绘制多边形

【思考题】 下面程序绘制什么样的图形?

#include <GL/glut.h>

void display()

{

glClear(GL_COLOR_BUFFER_BIT);

glBegin(GL_POLYGON);

glVertex2f(-0.5,-0.5);

glVertex2f(-0.5,0.5);

glVertex2f(0.5,0.5);

glVertex2f(0.5,-0.5);

glEnd();

glFlush();

}

int main(int argc,char** argv)

{

glutInit(&argc,argv);

glutCreateWindow("simple");

glutDisplayFunc(display);

glutMainLoop();

}

Page 7: 3 OpenGL计算机图形学与动画技术86 编译运行,绘制的具有真实感的球,如图3-1(a)所示。 OpenGL 函数主要包含在两个通常叫做gl 与glu 的库中,前者称为核心库;后者称

计算机图形学与动画技术

90

【例 3-4】 绘制一个白色背景的红色多边形。

程序清单如下:

#include <GL/glut.h>

void display()

{

glClear(GL_COLOR_BUFFER_BIT);

glBegin(GL_POLYGON);

glVertex2f(-0.6,-0.6); //4个顶点

glVertex2f(-0.6,0.6);

glVertex2f(0.6,0.6);

glVertex2f(0.6,-0.6);

glEnd();

glFlush();

}

void init()

{

glClearColor(1.0,1.0,1.0,0.0); //设置背景色,前 3个参数都是 1则为白色

glColor3f(1.0,0.0,0.0); //绘图颜色

}

int main(int argc,char** argv)

{

glutInit(&argc,argv);

glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB);

glutInitWindowSize(500, 500);

glutInitWindowPosition(0, 0);

glutCreateWindow("simple");

glutDisplayFunc(display);

init();

glutMainLoop();

}

编译运行该程序,结果如图 3-6(a)所示。

【例 3-5】 改进例 3-4程序,绘制一个白色背景下的红色五角星。

#include <glut.h>

#include <math.h>

void display()

{

glClear(GL_COLOR_BUFFER_BIT);

glBegin(GL_POLYGON); //一共 10个顶点

double y=sin(3.14/5)*tan(3.14/5)-cos(3.14/5); //计算顶点用

glVertex2f(0,y);

glVertex2f(-sin(3.14/5),-cos(3.14/5));

glVertex2f(cos(3.14/10)*y,sin(3.14/10)*y);

Page 8: 3 OpenGL计算机图形学与动画技术86 编译运行,绘制的具有真实感的球,如图3-1(a)所示。 OpenGL 函数主要包含在两个通常叫做gl 与glu 的库中,前者称为核心库;后者称

第 3章 OpenGL

91

glVertex2f(-cos(3.14/10),sin(3.14/10));

glVertex2f(sin(3.14/5)*y,-cos(3.14/5)*y);

glVertex2f(0,1);

glVertex2f(-sin(3.14/5)*y,-cos(3.14/5)*y);

glVertex2f(cos(3.14/10),sin(3.14/10));

glVertex2f(-cos(3.14/10)*y,sin(3.14/10)*y);

glVertex2f(sin(3.14/5),-cos(3.14/5));

glEnd();

glFlush();

}

void init()

{

glClearColor(1.0,1.0,1.0,0.0);

glColor3f(1.0,0.0,0.0);

}

void main(int argc,char** argv)

{

glutInit(&argc,argv);

glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB);

glutInitWindowSize(500, 500);

glutInitWindowPosition(0, 0);

glutCreateWindow("star");

glutDisplayFunc(display);

init();

glutMainLoop();

}

编译运行结果如图 3-6(b)所示。

图 3-6 绘制红色多边形与五角星

【例 3-6】 绘制点。

把例 3-5 等程序中的 glBegin(GL_POLYGON)改为 glBegin(GL_POINTS)就可以绘制

点。例如设计下面程序:

#include <GL/glut.h>

Page 9: 3 OpenGL计算机图形学与动画技术86 编译运行,绘制的具有真实感的球,如图3-1(a)所示。 OpenGL 函数主要包含在两个通常叫做gl 与glu 的库中,前者称为核心库;后者称

计算机图形学与动画技术

92

void display()

{

glClear(GL_COLOR_BUFFER_BIT);

glPointSize(15.0); //设置点的大小

glBegin(GL_POINTS);

glColor3f(0.0,0.0,0.0); //设置点的颜色,用 3个浮点数(红绿蓝)表示颜色

glVertex2f(-0.6,-0.6); //两个浮点数表示的平面(顶)点

glColor3f(1.0,0.0,0.0);

glVertex2f(-0.6,0.6);

glColor3f(0.0,0.0,1.0);

glVertex2f(0.6,0.6);

glColor3f(0.0,1.0,0.0);

glVertex2f(0.6,-0.6);

glEnd();

glFlush();

}

int main(int argc,char** argv)

{

glutInit(&argc,argv);

glutCreateWindow("Points");

glutDisplayFunc(display);

glClearColor(1.0,1.0,1.0,0.0);

glutMainLoop();

}

程序运行后,绘制的结果如图 3-7所示。

【例 3-7】 绘制直线段。

如果把上面例题程序中的 glBegin(GL_POLYGON)改为 glBegin(GL_LINES)(其他不

改变)就可以根据给出的点绘制线段。例如,例 3-5 改后绘制图 3-8(a)所示图形,

例 3-6改完后绘制图 3-8(b)所示图形。

观察图形会发现,图 3-8(b)绘制的直线颜色有变化,是通过顶点颜色进行插值计

算得到的。

如果把语句 glPointSize(15.0)修改为 glLineWidth(15.0),就会改变线的宽度,绘制如

图 3-8(c)所示的图形。

如果把参数 GL_LINES 修改为 GL_LINE_STRIP,那么每条线段的终点都是下一条

线段的起点,因此绘制一个连续的折边图形。如果把参数 GL_LINES修改为 GL_LINE_

LOOP,那么除了与 GL_LINE_STRIP一样连接线段外,还把最后一个顶点自动连接到第

一个顶点上。实际上就是绘制线框多边形。

另外,如果 glBegin(GL_POINTS)修改为 glBegin(GL_TRIANGLES),就会将 glBegin

与 glEnd 之间的每 3 个连续的顶点视为一个三角形,多余顶点会被忽略。而参数

GL_QUADS将 glBegin与 glEnd之间的每 4个连续的顶点视为一个四边形。

图 3-7 绘制不同颜色的点

Page 10: 3 OpenGL计算机图形学与动画技术86 编译运行,绘制的具有真实感的球,如图3-1(a)所示。 OpenGL 函数主要包含在两个通常叫做gl 与glu 的库中,前者称为核心库;后者称

第 3章 OpenGL

93

图 3-8 绘制线段

此外,类似的参数还有 GL_TRIANGLES_STRIP、GL_TRIANGLES_FAN、GL_

QUADS_STRIP等。

3.1.3 三维正方体绘制

【例 3-8】 绘制正方体线框图。

程序清单如下:

#include <GL/glut.h>

void display()

{

glClear(GL_COLOR_BUFFER_BIT);

glMatrixMode(GL_MODELVIEW);

glLoadIdentity();

gluLookAt(1,1,1,0,0,0,0,1,0);

glutWireCube(3); //3表示边长

glutSwapBuffers();

}

void reshape(int w,int h)

{

glViewport(0,0,w,h);

glMatrixMode(GL_PROJECTION);

glLoadIdentity();

glOrtho(-4.0,4.0,-4.0,4.0,-4.0,4.0);

}

void init()

{

glClearColor(1.0,1.0,1.0,1.0);

glColor3f(0,0,0);

glEnable(GL_LIGHTING);

glEnable(GL_LIGHT0);

}

int main(int argc,char** argv)

{