OpenGL学习:第一课

OpenGL学习:第一课

先了解一下OpenGL中对数据类型的定义,对后面使用一些库函数会有所帮助的。

打开gl.h文件,就可以看到OpenGL定义的一些基本数据类型,如下所示:

typedef unsigned int GLenum;
typedef unsigned char GLboolean;
typedef unsigned int GLbitfield;
typedef signed char GLbyte;
typedef short GLshort;
typedef int GLint;
typedef int GLsizei;
typedef unsigned char GLubyte;
typedef unsigned short GLushort;
typedef unsigned int GLuint;
typedef float GLfloat;
typedef float GLclampf;
typedef double GLdouble;
typedef double GLclampd;
typedef void GLvoid;

先从最简单的学习。

点是OpenGL中最基本最简单的图元,它不像数学中的点是要无穷小的,它是有大小的,大小默认为1个像素,但也可以改变。

改变一个点的大小,函数名称为glPointSize,其函数声明如下:

WINGDIAPI void APIENTRY glPointSize (GLfloat size);

你仍然可以到gl.h中查看该函数的声明。

函数声明中,size是点的大小,默认值为1.0f,单位为“像素”,而且,size必须要大于0.0f,原因很简单了,如果等于0了,你又怎么能在图形显示设备上看到点的存在呢。

为了学习方便,使用VC 6.0进行调试学习。

首先,新建一个Win32 Console Application,切换到Fileview视图,在Source Files中新建一个C++源文件,然后就可以在这个源文件中进行调试学习。

第一个简单的程序如下所示:

#include <windows.h>
#include <GL/glut.h>

void drawPoint(void) {
glClear(GL_COLOR_BUFFER_BIT);
glPointSize(5.0f);
glBegin(GL_POINTS);
   glVertex2f(0.0f,0.0f);
glEnd();
glFlush();
}

int main(int argc, char *argv[]) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE);
glutInitWindowPosition(100,100);
glutInitWindowSize(400,400);
glutCreateWindow("OpenGL基本图元:点");
glutDisplayFunc(&drawPoint);
glutMainLoop();
return 0;
}

编译并运行,可以看到黑色的窗口中显示了一个白色点的效果:

由于初学,对上面的程序作一些必要的解释。  

这种以glut开头的函数都是OpenGL的GLUT工具包所提供的函数。

下面对程序中用到的一些函数(库函数和自定义函数)进行说明:

一、自定义void drawPoint(void)函数

这个是我们自己编写的函数,需要在main()函数中调用,从而执行函数定义的功能。 函数的功能就是在窗口中画一个点,点的坐标是(0.0f,0.0f),即窗口的中心位置处;点的大小为5.f个像素。

函数中,首先调用库函数glClear(),该函数的声明如下:

WINGDIAPI void APIENTRY glClear (GLbitfield mask);

函数接受一个GLbitfield类型参数;函数的功能是清除指定的缓存。

这里需要说明的是,函数的参数可以是一个线性组合,含义是可以一次清除多个缓存,因为在图形渲染的过程中,可能存在多个缓存,根据需要进行设置。

例如,清除颜色缓存和深度缓存,可以使用下面的调用:

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

函数参数mask可以是如下值:

GL_COLOR_BUFFER_BIT            颜色缓存   
GL_DEPTH_BUFFER_BIT            深度缓存   
GL_ACCUM_BUFFER_BIT            累加缓存   
GL_STENCIL_BUFFER_BIT          模板缓存

然后,调用glPointSize()函数,设置点的大小,函数声明如下:

WINGDIAPI void APIENTRY glPointSize (GLfloat size);

接着,开始执行画点的操作了。

在OpenGL中进行画图的时候,必须通过使用启用/关闭模式来实现。也就是说,在画图之前要打开,在画图完毕后要关闭,正好对应了glBegin()和glEnd()两个函数:

glBegin()函数的声明如下所示:

WINGDIAPI void APIENTRY glBegin (GLenum mode);

函数参数指定了一种绘图模式mode,具体取值可以是下面之一:

CL_POINTS                            一系列独立的点        
CL_LINES                               每两点相连成为险段   
CL_POLYGON                        简单、凸多边形的边界   
CL_TRIANGLES                   三点相连为一个三角形   
CL_QUADS                            四点相连为一个四边形   
CL_LINE_STRIP                   顶点相连为一折线   
CL_LINE_LOOP                   顶点相连为一折线,并将最后一点与第一点相连   
CL_TRIANGLE_STRIP          相连的三角形带   
CL_TRIANGLE_FAN             相连的三角形扇形   
CL_QUAD_STRIP                 相连的四边形带  

函数glEnd()的声明如下所示:

WINGDIAPI void APIENTRY glEnd (void);

画图只能选择一种模式,可以在glBegin()函数与glEnd()函数之间进行操作。

在glBegin()函数与glEnd()函数之间,调用画点函数glVertex2f(),其声明如下所示:

WINGDIAPI void APIENTRY glVertex2f (GLfloat x, GLfloat y);

函数指定了一个二维坐标(x,y),要在该坐标处进行画点操作。另外,OpenGL库还提供了更多的画点的函数,如下所示:

WINGDIAPI void APIENTRY glVertex2d (GLdouble x, GLdouble y);
WINGDIAPI void APIENTRY glVertex2dv (const GLdouble *v);
WINGDIAPI void APIENTRY glVertex2f (GLfloat x, GLfloat y);
WINGDIAPI void APIENTRY glVertex2fv (const GLfloat *v);
WINGDIAPI void APIENTRY glVertex2i (GLint x, GLint y);
WINGDIAPI void APIENTRY glVertex2iv (const GLint *v);
WINGDIAPI void APIENTRY glVertex2s (GLshort x, GLshort y);
WINGDIAPI void APIENTRY glVertex2sv (const GLshort *v);
WINGDIAPI void APIENTRY glVertex3d (GLdouble x, GLdouble y, GLdouble z);
WINGDIAPI void APIENTRY glVertex3dv (const GLdouble *v);
WINGDIAPI void APIENTRY glVertex3f (GLfloat x, GLfloat y, GLfloat z);
WINGDIAPI void APIENTRY glVertex3fv (const GLfloat *v);
WINGDIAPI void APIENTRY glVertex3i (GLint x, GLint y, GLint z);
WINGDIAPI void APIENTRY glVertex3iv (const GLint *v);
WINGDIAPI void APIENTRY glVertex3s (GLshort x, GLshort y, GLshort z);
WINGDIAPI void APIENTRY glVertex3sv (const GLshort *v);
WINGDIAPI void APIENTRY glVertex4d (GLdouble x, GLdouble y, GLdouble z, GLdouble w);
WINGDIAPI void APIENTRY glVertex4dv (const GLdouble *v);
WINGDIAPI void APIENTRY glVertex4f (GLfloat x, GLfloat y, GLfloat z, GLfloat w);
WINGDIAPI void APIENTRY glVertex4fv (const GLfloat *v);
WINGDIAPI void APIENTRY glVertex4i (GLint x, GLint y, GLint z, GLint w);
WINGDIAPI void APIENTRY glVertex4iv (const GLint *v);
WINGDIAPI void APIENTRY glVertex4s (GLshort x, GLshort y, GLshort z, GLshort w);
WINGDIAPI void APIENTRY glVertex4sv (const GLshort *v);
WINGDIAPI void APIENTRY glVertexPointer (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);

有必要对这些函数名称的格式进行一下说明:

数字表示参数的个数,字母表示参数的类型,   
s 表示16位整数(OpenGL中将这个类型定义为GLshort),   
i 表示32位整数(OpenGL中将这个类型定义为GLint和GLsizei),   
f 表示32位浮点数(OpenGL中将这个类型定义为GLfloat和GLclampf),   
d 表示64位浮点数(OpenGL中将这个类型定义为GLdouble和GLclampd)。   
v 表示传递的几个参数将使用指针的方式。

这些函数除了参数的类型和个数不同以外,功能是相同的。

例如,我们要实现一个画点功能例子:画出9个点,void showPoint(void)函数实现如下所示:

void drawPoint(void) {
glClear(GL_COLOR_BUFFER_BIT);
glPointSize(5.0f);
glBegin(GL_POINTS);
   glVertex2f(-0.5f,0.5f);
   glVertex2f(0.0f,0.5f);
   glVertex2f(0.5f,0.5f);
   glVertex2f(-0.5f,0.0f);
   glVertex2f(0.0f,0.0f);
   glVertex2f(0.5f,0.0f);
   glVertex2f(-0.5f,-0.5f);
   glVertex2f(0.0f,-0.5f);
   glVertex2f(0.5f,-0.5f);
glEnd();
glFlush();
}

效果如下所示:

同样,我们可以把这9个点放在一个数组中,然后调用WINGDIAPI void APIENTRY glVertex2fv (const GLfloat *v);函数,如下所示:

void drawPoint(void) {
glClear(GL_COLOR_BUFFER_BIT);
glPointSize(5.0f);
const GLfloat vertex[9][2] = {
   {-0.5f,0.5f},
   {0.0f,0.5f},
   {0.5f,0.5f},
   {-0.5f,0.0f},
   {0.0f,0.0f},
   {0.5f,0.0f},
   {-0.5f,-0.5f},
   {0.0f,-0.5f},
   {0.5f,-0.5f}
};
glBegin(GL_POINTS);
for(int i=0;i<9;i++) {
   glVertex2fv(vertex[i]);
}
glEnd();
glFlush();
}

先构造了一个二维数组vertex,然后通过for循环,迭代出每个点的坐标,填充glVertex2fv()的参数即可以画出9个点,效果同上面相同。

最后,调用了glFlush(),将执行该函数调用之前的所有命令,即将所绘制的图形呈现在图形设备上。如果你没有调用它,就不会看到在在glBegin()函数与glEnd()函数之间进行的绘图操作的执行效果。

二、int main(int argc, char *argv[])

主函数中,主要是完成初始化和图形显示的任务。主函数中调用到的函数说明如下:

第一个:函数glutInit()进行GLUT库的初始化工作,它位于glut.h文件中,声明如下所示:

GLUTAPI void APIENTRY glutInit(int *argcp, char **argv);

函数的两个参数对应于入口主函数的两个参数,只是第一个参数用了指针来传递地址。

第二个:函数glutInitDisplayMode()用来设置GLUT库初始化显示模式,声明如下所示:

GLUTAPI void APIENTRY glutInitDisplayMode(unsigned int mode);

参数mode可以指定如下参数:

GLUT_RGB (表示使用RGB颜色)
GLUT_INDEX(表示使用索引颜色)
GLUT_SINGLE(表示使用单缓冲)
GLUT_DOUBLE(使用双缓冲)

第三个:函数glutInitWindowPosition()设置图形在窗口中的显示位置,其声明如下所示:

GLUTAPI void APIENTRY glutInitWindowPosition(int x, int y);

参数指定了一个坐标(x,y)。

第四个:函数glutInitWindowSize()设置显示窗口的尺寸,其声明如下所示:

GLUTAPI void APIENTRY glutInitWindowSize(int width, int height);

参数指定了一对值,表示显示窗口的宽度和高度,单位为像素。

第五个:函数glutCreateWindow()创建显示窗口的标题,其声明如下所示:

GLUTAPI int APIENTRY glutCreateWindow(const char *title);

参数指定了一个字符串,表示窗口的标题。

第六个:函数glutDisplayFunc()根据指定的回调函数,当进行显示的时候执行回调函数。其声明如下所示:

GLUTAPI void APIENTRY glutDisplayFunc(void (GLUTCALLBACK *func)(void));

可以将我们自定义的画图操作的函数的地址传递进来,执行画图操作。

第七个:函数glutMainLoop()进行一个消息循环,窗口被创建后,并不立即显示到屏幕上。需要调用glutMainLoop才能看到窗口。其声明如下所示:

GLUTAPI void APIENTRY glutMainLoop(void);

三、补充知识

RGBA颜色模型:

例如,函数void glClearColor(GLfloat r,GLfloat g,GLfloat b,GLfloat a)用于设置指定窗口的清除颜色,这里的参数使用的就是RGBA颜色模型,其中r,g,b用于设置RGB颜色模型的三个分量,a为透明度设置。这里r、g、b、a的取值范围是0.0~1.0。

绘图模式的开启/关闭:

OpenGL要求,指定顶点的命令必须包含在glBegin函数之后,glEnd函数之前(否则指定的顶点将被忽略)。并由glBegin来指明如何使用这些点。

在glBegin和glEnd之间,只有以下函数是有效的,其它函数全部会被忽略:

glVertex*   
glColor*   
glIndex*   
glSecondaryColor*   
glNormal*   
glMaterial*   
glFogCood*   
glTexCood*   
glMultiTexCood*   
glEdgeFlag*   
glArrayElement*   
glEvalCoord*   
glEvalPoint*   
glCallList   
glCallLists  

其中*表示所有可能的命令格式,比如:glVertex3f(),glVertex2d()等等。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值