OpenGL简介
是在SGI等多家世界闻名的计算机公司的倡导下,以SGI的GL三维图形库为基础制定的一个通用共享的开放式三维图形标准。是图形硬件的一个软件接口。
OpenGL特点
OpenGL是一个开放的三维图形软件包,它独立于窗口系统和操作系统,以它为基础开发的应用程序可以十分方便地在各种平台间移植。
OpenGL可以与Visual C++紧密接口,便于实现有关计算和图形算法,可保证算法的正确性和可靠性。
OpenGL使用简便,效率高。
vs环境下OpenGL函数库配置
加载glut库
把过glut32.lib拷贝到VC的安装目录下的lib文件夹中:如D:\Program Files\Microsoft Visual Studio\VC98\Lib
把glut.h拷贝到VC的安装目录下的Include\GL文件夹中:如:D:\Program Files\Microsoft Visual Studio\VC98\Include\GL
把glut32.dll拷贝到C:\WINDOWS\system32
OpenGL函数的命名规则
一般的函数命名如下:
<前缀><根函数><参数数目><参数类型>
前缀有gl、glu、aux、glut、wgl、glx、agl等等,分别表示该函数属于OpenGL那个开发库等。所谓开发库,要知道原生的OpenGL是跨平台的,跨平台意味着很多功能是无法实现的,比如说Windows和X-Window的窗口实现机制是不同的,OpenGL并不关心这些东西,只管画图。所以,OpenGL并没有窗口函数,比如无法创建窗口,无法获得输入……这些东西都需要其他的函数库来实现。用OpenGL常用的工具函数库来实现。
我们主要使用两种,一个是GLU库,它提供了比较基础的命令的封装,可以很简单的实现比较多的复杂功能;而另外一个就是GLUT,glut是不依赖于窗口平台的OpenGL工具包,目的是隐藏不同窗口平台API的复杂度,提供更为复杂的绘制功能,我们会大量的使用它。
OpenGL内部数据都是以float的形式存放的,如果使用double会对性能有一定的影响。
初始化窗口
glutInit()
是用glut来初始化OpenGL的,所有的问题都交给这个函数吧,基本不用管,虽说可以接受参数的,基本无用。
glutInitDisplayMode(MODE)
非常重要,这里告诉系统我们需要一个怎样显示模式。至于其参数GLUT_RGBA就是使用(red, green, blue)的颜色系统。有没有写错?这里有个A啊,不应该是(red, green, blue, alpha)么?大概是历史原因,GLUT_RGBA和GLUT_RGB是其实是等价的(坑爹啊),要想实现Alpha还得用其他的参数。而GLUT_SINGLE意味着所有的绘图操作都直接在显示的窗口执行,相对的,我们还有一个双缓冲的窗口,对于动画来说非常合适。
glutInitWindowSize(400, 400)
这个函数很容易理解,设置出现的窗口的大小。实际上还有个glutInitWindowPosition()也很常用,用来设置窗口出现的位置。
glutCreateWindow(“First”)
,一旦调用了,就出现一个窗口了,参数就是窗口的标题。
glutDisplayFunc(func)
是glut非常讨人喜欢的一个功能,它注册了一个函数,用来绘制OpenGL窗口,这个函数里就写着很多OpenGL的绘图操作等命令,也就是我们主要要学习的东西。
glutMainLoop()
,主循环,一旦调用了,我们的OpenGL就一直运行下去了。和很多程序中的主循环一样,不停的运行,画出即时的图像,处理输入等。
绘图
看看drawFunc里的几句话,这里是实际绘图的函数。
glClear(GL_COLOR_BUFFER_BIT)
是把先前的画面给清除,这基本是定律,每次重绘之前都要把原来的画面擦除,否则叠加起来什么都看不出了。glClear一看就知道是OpenGL原生的命令,而参数就是指明要清除的buffer。大家一定会有疑问,我们清除,不就是清除屏幕上的画面么,为什么还要指定?OpenGL的博大精深这里就体现出来了,buffer不仅仅有我们看到的那个GL_COLOR_BUFFER_BIT,OpenGL中还有其他的buffer类型,我们会在后面的章节讲到。
glutWireTeapot(0.5)
是glut提供的绘制犹他茶壶的工具函数,茶壶还是相当复杂的一个几何体,用这个函数一下子就画出来了,不过基本也就演示用用。这里是用的线模型,因为没有说光照和材质,如果glutSolidTeapot()画出来就成纸片儿了。
glFlush()
似乎不用多说,画了那么多,自然要刷新一下显示。不过,这里的刷新不仅仅是屏幕上的更新,实际上,它是处理OpenGL的渲染流水线,让所有排队中的命令得到执行。OpenGL的渲染流水线是一个很重要的概念,不过这里暂时还不打算多说明,否则对初学者来说,未免有些麻烦了。
glutSwapBuffers();
交换缓冲区(使用双缓存GLUT_DOUBLE,必须交换缓存才能显示)
小惊喜
glutIdleFunc(Func)
又是一个激动人心的函数,可以让OpenGL在闲暇之余,调用一下注册的函数,这是是产生动画的绝好方法
gluLookAt(0.0, 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
//定义一个视图矩阵,并与当前矩阵相乘(实现漫游)
void gluLookAt(GLdouble eyex, GLdouble eyey, GLdouble eyez, GLdouble centerx, GLdouble centery, GLdouble centerz, GLdouble upx, GLdouble upy, GLdouble upz);
该 函数定义一个视图 矩阵,并与当前矩阵相乘。
第一组eyex, eyey, eyez 相机在世界坐标的位置
第二组centerx, centery, centerz 相机镜头对准的物体在世界坐标的位置
第三组upx, upy, upz 相机向上的方向在世界坐标中的方向
你把相机想象成为你自己的脑袋:
第一组数据就是脑袋的位置
第二组数据就是眼睛看的物体的位置
第三组就是头顶朝向的方向(因为你可以歪着头看同一个物体)
OpenGL中维持着两套矩阵,一个是模型视图矩阵(model view matrix),另一个是投影矩阵(projection matrix)。
通过对OpenGL这两套矩阵的变换,我们可以得到各种投影效果
一些常用函数
glColor3f(1.0, 0.0, 0.0);
//画笔红色
glutReshapeFunc(reshape);
//窗口发生改变再渲染
glutMouseFunc(mouse);
glutMotionFunc(motion);
//处理当鼠标键摁下时,鼠标拖动的事件。当鼠标拖动时,将每一帧都调用一次这个函数 glLoadIdentity();
//重置当前模型观察矩阵
glPushMatrix();
//把刚刚的那个位置和角度保存进栈中(主要用于平移,旋转,缩放等)保存当前模型视图 glPopMatrix();
//根据保存的值恢复出位置,角度等 glRotatef(anglex, 1.0, 0.0, 0.0);
//以(x,y,z)向量为旋转轴旋转angle度 glScalef(1.0,1.0,1.0);
//每一点坐标分别乘以x,y,z倍(缩放)
glViewport(0, 0, (GLsizei)w, (GLsizei)h);
//负责把视景体截取的图像按照怎样的高和宽显示到屏幕上 glMatrixMode(GL_PROJECTION);
//设置当前矩阵模式:对投影矩阵应用随后的矩阵操作 与glLoadIdentity()一同使用
glLoadIdentity();
//重置当前模型观察矩阵:将当前的用户坐标系的原点移到了屏幕中心 >>
gluPerspective(60.0, (GLfloat)w /(GLfloat)h, 1.0, 20.0);glMatrixMode(GL_MODELVIEW);
//创建一个投影矩阵并且与当前矩阵相乘,得到的矩阵设定为当前变换,但要先通过glMatrixMode设定成投影矩阵才会得到想要的投影矩阵变换
glLoadIdentity();
//设置当前矩阵模式:对模型视景矩阵堆栈应用随后的矩阵操作 另GL_TEXTURE参数,是对纹理矩阵堆栈应用随后的矩阵操作
gluLookAt(0.0, 0.0, 5.0, 0.0, 0.0,0.0, 0.0, 1.0, 0.0);`
//重置当前模型观察矩阵:将当前的用户坐标系的原点移到了屏幕中心
//定义一个视图 与当阵相乘()
用OpenGL编写程序的模板基本模板
//主函数
int main(int argc, char* argv[])
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH); //设置显示模式(颜色、缓冲区等)
glutCreateWindow(“A Simple Example”); //创建窗口
SetupRC(); //初始化渲染环境
glutDisplayFunc(RenderScene); //调用场景渲染函数
glutReshapeFunc(ChangeSize); //窗口发生变化
glutMainLo(); //程序开始事件处理
}
几何图元的绘制
glBegin(GL_TRIANGLES); //三角形
glVertex3f(0.0f,1.0f,0.0f);
glVertex3f(-1.0f,-1.0f,0.0f);
glVertex3f(1.0f,-1.0f,0.0f);
glEnd();
glBegin(GL_QUADS); //四边形
glVertex3f(-1.0f,1.0f,0.0f);
glVertex3f(1.0f,1.0f,0.0f);
glVertex3f(1.0f,-1.0f,0.0f);
glVertex3f(-1.0f,-1.0f,0.0f);
glEnd();
下面是一个完整例子:
3D场景绘制2D透明缩放矩阵信息面板
#include
#include
#include
//输出模式,0-单缓存模式;非0双缓存模式
#define OUTPUT_MODE 1
float scale = 0.0;
bool add = true;
unsigned char axle = 'x';
void init(void)
{
//glClearColor函数设置好清除颜色,glClear利用glClearColor函数设置好的当前清除颜色设置窗口颜色
glClearColor(1.0, 1.0, 0.8, 1.0);
}
void display(void)
{
printf("scale=%f, axle=%c\n", scale, axle);
glClear(GL_COLOR_BUFFER_BIT);
//配置缩放比例大小scale
scale = (add ? scale + 0.1 : scale - 0.1);
if (scale >= 2.0)
{
add = false;
}
else if (scale <= 0.0) {
add = true;
}
//开始绘画
glPushMatrix();
{
if (axle == 'x') {
glScalef(scale, 1, 1);
}
else if (axle == 'y') {
glScalef(1, scale, 1);
}
else if (axle == 'z') {
glScalef(1, 1, scale);
}
else {
glScalef(scale, scale, scale);
}
glColor3f(1.0, 0.0, 1.0); //画笔梅红色
glBegin(GL_POLYGON);
glVertex2f(-0.2, -0.2);
glVertex2f(-0.2, 0.2);
glVertex2f(0.2, 0.2);
glVertex2f(0.2, -0.2);
glEnd();
}
glPopMatrix();
glLoadIdentity(); //加载单位矩阵
glColor3f(0.0, 0.0, 1.0); //画笔蓝色
//--------画直线START--------
//画直线
glBegin(GL_LINES);
glVertex2f(-0.5, 0);
glVertex2f(0.5, 0);
glVertex2f(0, 0.5);
glVertex2f(0, -0.5);
glEnd();
//--------画直线E N D--------
if (OUTPUT_MODE == 0) {
glFlush();//单缓存GLUT_SINGLE时使用
}
else {
glutSwapBuffers();//因为使用的是双缓存GLUT_DOUBLE,所以这里必须要交换缓存才会显示
}
Sleep(50);
}
void reshape(int w, int h)
{
int offset = 50;
int dis = (w > h ? h : w) - offset * 2;
//配置显示物体屏幕的大小
glViewport(offset, offset, (GLsizei)dis, (GLsizei)dis);
printf("reshape: w=%d, h=%d, dis=%d\n", w, h, dis);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-1.5, 1.5, -1.5, 1.5, 0, 10);
//gluOrtho2D(-1.5, 1.5, -1.5, 1.5);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
void keyboard(unsigned char key, int x, int y)
{
switch (key) {
case 'x':
case 'X':
axle = 'x';
glutPostRedisplay();
break;
case 'y':
case 'Y':
axle = 'y';
glutPostRedisplay();
break;
case 'z':
case 'Z':
axle = 'z';
glutPostRedisplay();
break;
case 'a':
case 'A':
axle = 'a';
glutPostRedisplay();
break;
default:
break;
}
printf("按键%c\n", key);
}
int main(int argc, char *argv[])
{
printf("可通过按键xyza控制图形按哪一轴缩放\n");
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGB | (OUTPUT_MODE == 0 ? GLUT_SINGLE : GLUT_DOUBLE));
glutInitWindowPosition(100, 100);
glutInitWindowSize(400, 400);
glutCreateWindow("第一个 OpenGL 程序");
init();
glutDisplayFunc(&display);
glutIdleFunc(display); //程序空闲的时候调用display(设置不断调用显示函数)
glutReshapeFunc(reshape);
// glutKeyboardFunc(keyboard);
glutMainLoop();
return 0;
}