数据类型和函数名
OpenGL的数据类型定义可以与其它语言一致,但建议在ANSI C下最好使用以下定义的数据类型,例如GLint、GLfloat等。
前缀 | 数据类型 | 相应C语言类型 | OpenGL类型 |
---|---|---|---|
b | 8-bit integer | signed char | GLbyte |
s | 16-bit integer | short | GLshort |
i | 32-bit integer | long | GLint,GLsizei |
f | 32-bit floating-point | float | GLfloat,GLclampf |
d | 64-bit floating-point | double | GLdouble,GLclampd |
ub | 8-bit unsigned integer | unsigned char | GLubyte,GLboolean |
us | 16-bit unsigned integer | unsigned short | GLushort |
ui | 32-bit unsigned integer | unsigned long | GLuint,GLenum,GLbitfield |
从上表可以看出,OpenGL的库函数命名方式很有规律,了解这种规律后阅读和编写程序都比较容易方便。
首先,每个库函数有前缀gl、glu、glx或aux,表示此函数分属于基本库、实用库、X窗口扩充库或辅助库,其后的函数名头字母大写,后缀是参数类型的简写,取i、f。例如:
glVertex2i(2,4);
glVertex3f(2.0,4.0,5.0);
如上,有的函数参数类型后缀前带有数字2、3、4。其中,2代表二维,3代表三维,4代表alpha值。
除此之外,有些OpenGL函数最后带一个字母v,表示函数参数可用一个指针指向一个向量(或数组)来替代一系列单个参数值。下面两种格式都表示设置当前颜色为红色,二者等价。
glColor3f(1.0,0.0,0.0);
float color_array[]={1.0,0.0,0.0};
glColor3fv(color_array);
除了以上基本命名方式外,还有一种带“”星号的表示方法,例如glColor(),它表示可以用函数的各种方式来设置当前颜色。同理,glVertex*v()表示用一个指针指向所有类型的向量来定义一系列顶点坐标值。
示例
下面一个示例程序,也是一个初学者学习的第一个示例程序。源码如下:
// main.cpp
// opengl_progress_struct
#include <GLUT/GLUT.h>
#include <OpenGL/OpenGL.h>
// 初始化参数
void init() {
glClearColor(0.1, 0.1, 0.4, 0.0);
glShadeModel(GL_SMOOTH);
}
// 绘图回调函数
void display() {
// 清除之前帧数据
glClear(GL_COLOR_BUFFER_BIT);
// 绘制三角形
glBegin(GL_TRIANGLES);
glColor3f(1, 0, 0);
glVertex3f(-1, -1, -5);
glColor3f(0, 1, 0);
glVertex3f(1, -1, -5);
glColor3f(0, 0, 1);
glVertex3f(0, 1, -5);
glEnd();
// 执行绘图命令
glFlush();
}
// 窗口大小变化回调函数
void reshape(int w, int h) {
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60.0, (GLfloat)w/(GLfloat)h, 0.1, 100000.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
int main(int argc, const char * argv[]) {
// 初始化显示模式
glutInit(&argc, const_cast<char **>(argv));
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
// 初始化窗口
glutInitWindowSize(500, 500);
glutInitWindowPosition(100, 100);
glutCreateWindow(argv[0]);
init();
glutReshapeFunc(reshape);
glutDisplayFunc(display);
// 开始主循环绘制
glutMainLoop();
return 0;
}
运行效果如下:
几何图形绘制
在空间直角坐标系中,任意一点可用一个三维坐标矩阵[x y z]表示。如果将该点用一个四维坐标的矩阵[Hx Hy Hz H]表示时,则称为齐次坐标表示方法。在齐次坐标中,最后一维坐标H称为比例因子。
在OpenGL中,二维坐标点全看作三维坐标点,所有点都用齐次坐标来描述,统一作为三维齐次点来处理。每个齐次点用一个向量(x, y, z, w)表示,其中四个元素全不为零。齐次点具有下列几个性质:
1)如果实数a非零,则(x, y, x, w)和(ax, ay, az, aw)表示同一个点,类似于x/y = (ax)/( ay)。
2)三维空间点(x, y, z)的齐次点坐标为(x, y, z, 1.0),二维平面点(x,y)的齐次坐标为(x, y, 0.0, 1.0)。
3)当w不为零时,齐次点坐标(x, y, z, w)即三维空间点坐标(x/w, y/w, z/w);当w为零时,齐次点(x, y, z, 0.0)表示此点位于某方向的无穷远处。
注意:OpenGL中指定w大于或等于0.0。
几何图形
在集合图形中,会涉及到几个概念:
点
用浮点值表示的点称为顶点(Vertex)。所有顶点在OpenGL内部计算时都作为三维点处理,用二维坐标(x, y)定义的点在OpenGL中默认z值为0。所有顶点坐标用齐次坐标(x, y, z, w) 表示,如果w不为0.0,这些齐次坐标表示的顶点即为三维空间点(x/w, y/w, z/w)。编程者可以自己指定w值,但很少这样做。一般来说,w缺省为1.0。
线
在OpenGL中,线代表线段(Line Segment),不是数学意义上的那种沿轴两个方向无限延伸的线。这里的线由一系列顶点顺次连结而成,有闭合和不闭合两种。
多边形
OpenGL中定义的多边形是由一系列线段依次连结而成的封闭区域。这些线段不能交叉,区域内不能有空洞,多边形必须在凸多边形,否则不能被OpenGL函数接受。
绘制图元
定义顶点
在OpenGL中,所有几何物体最终都由有一定顺序的顶点集来描述的。函数glVertex{234}{sifd}v可以用二维、三维或齐次坐标定义顶点。例如:
glVertex2s(2,3);
glVertex3d(0.0,1.0,3.1414926535);
glVertex4f(2.4,1.0,-2.2,2.0);
GLfloat pp[3]={5.0,2.0,10.2};
glVertex3fv(pp);
第一例子表示一个空间顶点(2, 3, 0),第二个例子表示用双精度浮点数定义一个顶点,第三个例子表示用齐次坐标定义一个顶点,其真实坐标为(1.2, 0.5, -1.1),最后一个例子表示用一个指针(或数组)定义顶点。
几何图元
在实际应用中,通常用一组相关的顶点序列以一定的方式组织起来定义某个几何图元,而不采用单独定义多个顶点来构造几何图元。在OpenGL中,所有被定义的顶点必须放在glBegain()和glEnd()两个函数之间才能正确表达一个几何图元或物体,否则,glVertex*()不完成任何操作。例如:
glBegin(GL_POLYGON);
glVertex2f(0.0,0.0);
glVertex2f(0.0,3.0);
glVertex2f(3.0,3.0);
glVertex2f(4.0,1.5);
glVertex2f(3.0,0.0);
glEnd();
以上这段程序定义了一个多边形,如果将glBegin()中的参数GL_POLYGON改为GL_POINTS,则图形变为一组顶点(5个)。
图元标志
点函数glBegin(GLenum mode)标志描述一个几何图元的顶点列表的开始,其参数mode表示几何图元的描述类型。所有类型及说明见下表:
类型 | 说明 |
---|---|
GL_POINTS | 单个顶点集 |
GL_LINES | 多组双顶点线段 |
GL_POLYGON | 单个简单填充凸多边形 |
GL_TRAINGLES | 多组独立填充三角形 |
GL_QUADS | 多组独立填充四边形 |
GL_LINE_STRIP | 不闭合折线 |
GL_LINE_LOOP | 闭合折线 |
GL_TRAINGLE_STRIP | 线型连续填充三角形串 |
GL_TRAINGLE_FAN | 扇形连续填充三角形串 |
GL_QUAD_STRIP | 连续填充四边形串 |
上面表用几何图形表示的化,如下图。
在glBegin()和glEnd()之间最重要的信息就是由函数glVertex*()定义的顶点,必要时也可为每个顶点指定颜色、法向、纹理坐标或其他,即调用相关的函数,如下表。
函数 | 说明 |
---|---|
glVertex*() | 设置顶点坐标 |
glColor*() | 设置当前颜色 |
glIndex*() | 设置当前颜色表 |
glNormal*() | 设置法向坐标 |
glCallList(),glCallLists() | 执行显示列表 |
glTexCoord*() | 设置纹理坐标 |
glEdgeFlag*() | 控制边界绘制 |
glMaterial*() | 设置材质 |
看一个示例:
glBegin(GL_POINTS);
glColor3f(1.0,0.0,0.0); /* red color */
glVertex(...);
glColor3f(0.0,1.0,0.0); /* green color */
glColor3f(0.0,0.0,1.0); /* blue color */
glVertex(...);
glVertex(...);
glEnd();
示例
为了更好的理解OpenGL几何图形的绘制,下面看一个综合的示例。
#include <GLUT/GLUT.h>
#include <OpenGL/OpenGL.h>
// 初始化参数
void init() {
glClearColor(0.1, 0.1, 0.4, 0.0);
glShadeModel(GL_SMOOTH);
}
void DrawMyObjects(void){
/* draw some points */
glBegin(GL_POINTS);
glColor3f(1.0,0.0,0.0);
glVertex2f(-10.0,11.0);
glColor3f(1.0,1.0,0.0);
glVertex2f(-9.0,10.0);
glColor3f(0.0,1.0,1.0);
glVertex2f(-8.0,12.0);
glEnd();
/* draw some line_segments */
glBegin(GL_LINES);
glColor3f(1.0,1.0,0.0);
glVertex2f(-11.0,8.0);
glVertex2f(-7.0,7.0);
glColor3f(1.0,0.0,1.0);
glVertex2f(-11.0,9.0);
glVertex2f(-8.0,6.0);
glEnd();
/* draw one opened_line */
glBegin(GL_LINE_STRIP);
glColor3f(0.0,1.0,0.0);
glVertex2f(-3.0,9.0);
glVertex2f(2.0,6.0);
glVertex2f(3.0,8.0);
glVertex2f(-2.5,6.5);
glEnd();
/* draw one closed_line */
glBegin(GL_LINE_LOOP);
glColor3f(0.0,1.0,1.0);
glVertex2f(7.0,7.0);
glVertex2f(8.0,8.0);
glVertex2f(9.0,6.5);
glVertex2f(10.3,7.5);
glVertex2f(11.5,6.0);
glVertex2f(7.5,6.0);
glEnd();
/* draw one filled_polygon */
glBegin(GL_POLYGON);
glColor3f(0.5,0.3,0.7);
glVertex2f(-7.0,2.0);
glVertex2f(-8.0,3.0);
glVertex2f(-10.3,0.5);
glVertex2f(-7.5,-2.0);
glVertex2f(-6.0,-1.0);
glEnd();
/* draw some filled_quandrangles */
glBegin(GL_QUADS);
glColor3f(0.7,0.5,0.2);
glVertex2f(0.0,2.0);
glVertex2f(-1.0,3.0);
glVertex2f(-3.3,0.5);
glVertex2f(-0.5,-1.0);
glColor3f(0.5,0.7,0.2);
glVertex2f(3.0,2.0);
glVertex2f(2.0,3.0);
glVertex2f(0.0,0.5);
glVertex2f(2.5,-1.0);
glEnd();
/* draw some filled_strip_quandrangles */
glBegin(GL_QUAD_STRIP);
glVertex2f(6.0,-2.0);
glVertex2f(5.5,1.0);
glVertex2f(8.0,-1.0);
glColor3f(0.8,0.0,0.0);
glVertex2f(9.0,2.0);
glVertex2f(11.0,-2.0);
glColor3f(0.0,0.0,0.8);
glVertex2f(11.0,2.0);
glVertex2f(13.0,-1.0);
glColor3f(0.0,0.8,0.0);
glVertex2f(14.0,1.0);
glEnd();
/* draw some filled_triangles */
glBegin(GL_TRIANGLES);
glColor3f(0.2,0.5,0.7);
glVertex2f(-10.0,-5.0);
glVertex2f(-12.3,-7.5);
glVertex2f(-8.5,-6.0);
glColor3f(0.2,0.7,0.5);
glVertex2f(-8.0,-7.0);
glVertex2f(-7.0,-4.5);
glVertex2f(-5.5,-9.0);
glEnd();
/* draw some filled_strip_triangles */
glBegin(GL_TRIANGLE_STRIP);
glVertex2f(-1.0,-8.0);
glVertex2f(-2.5,-5.0);
glColor3f(0.8,0.8,0.0);
glVertex2f(1.0,-7.0);
glColor3f(0.0,0.8,0.8);
glVertex2f(2.0,-4.0);
glColor3f(0.8,0.0,0.8);
glVertex2f(4.0,-6.0);
glEnd();
/* draw some filled_fan_triangles */
glBegin(GL_TRIANGLE_FAN);
glVertex2f(8.0,-6.0);
glVertex2f(10.0,-3.0);
glColor3f(0.8,0.2,0.5);
glVertex2f(12.5,-4.5);
glColor3f(0.2,0.5,0.8);
glVertex2f(13.0,-7.5);
glColor3f(0.8,0.5,0.2);
glVertex2f(10.5,-9.0);
glEnd();
}
// 绘图回调函数
void display() {
// 清除之前帧数据
glClear(GL_COLOR_BUFFER_BIT);
DrawMyObjects();
// 执行绘图命令
glFlush();
}
// 窗口大小变化回调函数
void reshape(int w, int h) {
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60.0, (GLfloat)w/(GLfloat)h, 0.1, 100000.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0, 0, 25, 0, 0, -1, 0, 1, 0);
}
int main(int argc, const char * argv[]) {
// 初始化显示模式
glutInit(&argc, const_cast<char **>(argv));
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
// 初始化窗口
glutInitWindowSize(500, 500);
glutInitWindowPosition(100, 100);
glutCreateWindow(argv[0]);
init();
glutReshapeFunc(reshape);
glutDisplayFunc(display);
// 开始主循环绘制
glutMainLoop();
return 0;
}
运行效果如下图: