Upload
others
View
14
Download
0
Embed Size (px)
Citation preview
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>
第 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);
}
计算机图形学与动画技术
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 把各个文件放到相应的文件夹中
第 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函数
计算机图形学与动画技术
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();
第 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();
}
计算机图形学与动画技术
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);
第 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>
计算机图形学与动画技术
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 绘制不同颜色的点
第 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)
{