opengl学习资料收集

更新时间:2024-01-16 17:15:01 阅读量: 教育文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

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 #include

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(\基本图元:点\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()等等。 OpenGL学习:第二课

OpenGL中,可以对基本图元进行颜色的设置。

先说一下,OpenGL中的基本图元。基本图元是构成图形的基本元素,在启动绘图模式的时候,使用函数glBegin(GLenum 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 单个简单填充凸多边形 多组独立填充三角形 多组独立填充四边形 不闭合折线 闭合折线 线型连续填充三角形串 扇形连续填充三角形串 连续填充四边形串 具体地,部分基本图元显示效果示例如图(来自互联网)所示:

颜色的设置,最简单地,可以直接调用例如函数glColor3f()进行颜色的设置,其声明如下所示:

WINGDIAPI void APIENTRY glColor3f (GLfloat red, GLfloat green, GLfloat blue);

这里就是指定了R、G、B三个颜色分量的值。

另外,可以在gl.h中看到更多设置颜色的函数声明,如下所示:

WINGDIAPI void APIENTRY glColor3b (GLbyte red, GLbyte green, GLbyte blue); WINGDIAPI void APIENTRY glColor3bv (const GLbyte *v); WINGDIAPI void APIENTRY glColor3d (GLdouble red, GLdouble green, GLdouble blue);

WINGDIAPI void APIENTRY glColor3dv (const GLdouble *v);

WINGDIAPI void APIENTRY glColor3f (GLfloat red, GLfloat green, GLfloat blue);

WINGDIAPI void APIENTRY glColor3fv (const GLfloat *v);

WINGDIAPI void APIENTRY glColor3i (GLint red, GLint green, GLint blue); WINGDIAPI void APIENTRY glColor3iv (const GLint *v);

WINGDIAPI void APIENTRY glColor3s (GLshort red, GLshort green, GLshort blue);

WINGDIAPI void APIENTRY glColor3sv (const GLshort *v);

WINGDIAPI void APIENTRY glColor3ub (GLubyte red, GLubyte green, GLubyte blue);

WINGDIAPI void APIENTRY glColor3ubv (const GLubyte *v);

WINGDIAPI void APIENTRY glColor3ui (GLuint red, GLuint green, GLuint blue);

WINGDIAPI void APIENTRY glColor3uiv (const GLuint *v);

WINGDIAPI void APIENTRY glColor3us (GLushort red, GLushort green, GLushort blue);

WINGDIAPI void APIENTRY glColor3usv (const GLushort *v);

WINGDIAPI void APIENTRY glColor4b (GLbyte red, GLbyte green, GLbyte blue, GLbyte alpha);

WINGDIAPI void APIENTRY glColor4bv (const GLbyte *v); WINGDIAPI void APIENTRY glColor4d (GLdouble red, GLdouble green, GLdouble blue, GLdouble alpha);

WINGDIAPI void APIENTRY glColor4dv (const GLdouble *v);

WINGDIAPI void APIENTRY glColor4f (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);

WINGDIAPI void APIENTRY glColor4fv (const GLfloat *v);

WINGDIAPI void APIENTRY glColor4i (GLint red, GLint green, GLint blue, GLint alpha);

WINGDIAPI void APIENTRY glColor4iv (const GLint *v);

WINGDIAPI void APIENTRY glColor4s (GLshort red, GLshort green, GLshort blue, GLshort alpha);

WINGDIAPI void APIENTRY glColor4sv (const GLshort *v);

WINGDIAPI void APIENTRY glColor4ub (GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha);

WINGDIAPI void APIENTRY glColor4ubv (const GLubyte *v);

WINGDIAPI void APIENTRY glColor4ui (GLuint red, GLuint green, GLuint blue, GLuint alpha);

WINGDIAPI void APIENTRY glColor4uiv (const GLuint *v);

WINGDIAPI void APIENTRY glColor4us (GLushort red, GLushort green,

GLushort blue, GLushort alpha);

WINGDIAPI void APIENTRY glColor4usv (const GLushort *v);

WINGDIAPI void APIENTRY glColorMask (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha);

WINGDIAPI void APIENTRY glColorMaterial (GLenum face, GLenum mode); WINGDIAPI void APIENTRY glColorPointer (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); 函数名称的格式说明如下:

数字表示参数的个数,字母表示参数的类型,

b 表示8位字符(OpenGL中将这个类型定义为GLubyte) s 表示16位整数(OpenGL中将这个类型定义为GLshort)

i 表示32位整数(OpenGL中将这个类型定义为GLint和GLsizei)

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

u 表示上述类型为无符号的,即unsigned,可以和上述字母进行组合 通过上节课中画点的例子,对每个点进行颜色的设置,代码如下所示: #include #include

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} };

const GLfloat color[9][3] = { // 定义颜色数组 {0.0f,0.0f,0.0f}, {0.0f,1.0f,0.0f}, {0.0f,0.0f,1.0f},

{0.35f,0.360f,0.782f}, {0.87f,0.87f,0.87}, {0.5f,0.5f,0.5f},

{1.0f,0.0f,0.0},

{0.0f,0.533f,0.457}, {1.0f,1.0f,1.0f} };

glBegin(GL_POINTS); for(int i=0;i<9;i++) {

glColor3fv(color[i]); // 在画点之前进行颜色设置 glVertex2fv(vertex[i]); // 画点 }

glEnd(); glFlush(); }

int main(int argc, char *argv[]) { glutInit(&argc, argv);

glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE); glutInitWindowPosition(100,100); glutInitWindowSize(400,400);

glutCreateWindow(\基本图元:点\glutDisplayFunc(&drawPoint); glutMainLoop(); return 0; }

编译并运行,效果如图所示:

需要注意的是,在画点之前最近进行的颜色设置才会生效。 画线

仍然利用上面的例子,只是将绘图模式改为画线。同时,将点的大小修改为15f,并使用函数glVertex3fv()进行点的设置,因此点就是三维坐标点,就要修改点数组为9*3数组,代码如下所示: #include #include

void drawLine(void) {

glClear(GL_COLOR_BUFFER_BIT); glPointSize(15.0f);

const GLfloat vertex[9][3] = { {-0.5f,0.5f,0.1f}, {0.0f,0.5f,0.2f}, {0.5f,0.5f,0.3f}, {-0.5f,0.0f,0.4f}, {0.0f,0.0f,0.5f}, {0.5f,0.0f,0.6f}, {-0.5f,-0.5f,0.7f}, {0.0f,-0.5f,0.8f},

{0.5f,-0.5f,0.9f} };

const GLfloat color[9][3] = { {0.8f,0.3f,0.2f}, {0.0f,1.0f,0.0f}, {0.0f,0.0f,1.0f},

{0.35f,0.360f,0.782f}, {0.87f,0.87f,0.87}, {0.5f,0.5f,0.5f}, {1.0f,0.0f,0.0},

{0.0f,0.533f,0.457}, {1.0f,1.0f,1.0f} };

glBegin(GL_LINES); // 启用画线模式 for(int i=0;i<9;i++) { glColor3fv(color[i]); glVertex3fv(vertex[i]); }

glEnd(); glFlush(); }

int main(int argc, char *argv[]) { glutInit(&argc, argv);

glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE); glutInitWindowPosition(100,100); glutInitWindowSize(400,400);

glutCreateWindow(\基本图元:线\glutDisplayFunc(&drawLine); glutMainLoop(); return 0; }

编译并运行,显示效果如图所示:

可以看到,一共画出了4条线,而我们用到了9个点,也就是说,画线的操作是这样执行的:按照在glBegin(GL_LINES)与glEnd()语句之间列出的点的顺序,每相邻的两个点画一条线,如果是奇数个点,那么最后一个点就不可能有另一个端点而画出线条,同时,这个点也不会在屏幕中单独显示出一个点的。 画线的时候,可以对线宽和线型进行设置。

对线宽设置调用函数glLineWidth(),该函数的声明如下所示: WINGDIAPI void APIENTRY glLineWidth (GLfloat width); 一个参数width指定了线条的宽度,即线条的粗细。

对线型进行设置可以调用函数glLineStipple(),该函数的声明如下所示: WINGDIAPI void APIENTRY glLineStipple (GLint factor, GLushort pattern); 第一个参数是一个乘数因子,主要对第二个参数而言的,第二个参数pattern是16位的整数。在使用某种指定的线型进行画线的时候,会计算factor与

pattern中每一个bit的乘积,即,使用factor次pattern中的某一位(bit)。其中factor的取值范围是[0,256],pattern一般使用16进制。

在启动使用某种线型模式的时候,需要调用glEnable()函数来启动,而使用glDisable()函数关闭这种模式。 下面写一个程序,如下所示: void drawLine(void) {

glClear(GL_COLOR_BUFFER_BIT);

glLineWidth(30.0f);

glEnable(GL_LINE_STIPPLE); // 启用虚线画线模式 glLineStipple(5,0xF0F0); // 设置画线样式 glBegin(GL_LINES);

glColor3f(1.0f,0.0f,0.0f); glVertex3f(-0.5f,0.5f,0.0f); glVertex3f(0.5f,0.5f,0.0f); glEnd();

glDisable(GL_LINE_STIPPLE);

glLineWidth(2.0f);

glEnable(GL_LINE_SMOOTH); // 启用平滑画线模式 glBegin(GL_LINES);

glColor3f(1.0f,1.0f,0.0f); glVertex3f(-0.5f,0.0f,0.0f); glVertex3f(0.5f,0.0f,0.0f); glEnd();

glDisable(GL_LINE_SMOOTH);

glLineWidth(7.0f);

glEnable(GL_LINE_STIPPLE); // 启用虚线画线模式 glLineStipple(3,0xA160); glBegin(GL_LINES);

glColor3f(0.0f,1.0f,0.0f); glVertex3f(-0.5f,-0.5f,0.0f); glVertex3f(0.5f,-0.5f,0.0f); glEnd();

glDisable(GL_LINE_STIPPLE); glFlush(); }

编译并运行,效果如图所示:

画多边形

OpenGL使用glBegin(GL_POLYGON);语句来启动画多边形,而且只能是凸多边形。 绘制多边形,调用glEnable(GL_POLYGON_STIPPLE)来启动多边形绘制模式,可以调用函数glPolygonStipple()来设置多边形绘制模式。该函数的声明如下: WINGDIAPI void APIENTRY glPolygonStipple (const GLubyte *mask); 参数mask是一个指向32x32位图的指针。与虚线绘制的道理一样,某位为1时绘制,为0时什么也不绘。注意,不用时用glDisable(GL_POLYGON_STIPPLE)关闭。

函数glPolygonMode()可以设置多边形的填充模式,声明如下:

WINGDIAPI void APIENTRY glPolygonMode (GLenum face, GLenum mode); 参数face用来指定要填充的是多变形的哪一个面,可以取值: GL_FRONT 正面(前面) GL_BACK 反面(背面)

GL_FRONT_AND_BACK 正面和反面

参数mode用来指定要对多边形进行填充的模式,可以取值: GL_POINT 轮廓点式多边形 GL_LINE 轮廓线式多边形 GL_FILL 全填充式多边形

下面是一个使用位图填充多边形的例子,代码如下所示: include #include

void drawPolygon(void) {

glClear(GL_COLOR_BUFFER_BIT);

GLubyte pattern[128] = { // 定义填充位图数组 0x00,0x01,0x80,0x00, 0x00,0x03,0xc0,0x00, 0x00,0x07,0xe0,0x00, 0x00,0x0f,0xf0,0x00, 0x00,0x1f,0xf8,0x00, 0x00,0x3f,0xfc,0x00, 0x00,0x7f,0xfe,0x00, 0x00,0xff,0xff,0x00, 0x01,0xff,0xff,0x80, 0x03,0xff,0xff,0xc0, 0x07,0xff,0xff,0xe0, 0x0f,0xff,0xff,0xf0, 0x1f,0xff,0xff,0xf8, 0x3f,0xff,0xff,0xfc, 0x7f,0xff,0xff,0xfe, 0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff, 0x7f,0xff,0xff,0xfe, 0x3f,0xff,0xff,0xfc, 0x1f,0xff,0xff,0xf8, 0x0f,0xff,0xff,0xf0, 0x07,0xff,0xff,0xe0, 0x03,0xff,0xff,0xc0, 0x01,0xff,0xff,0x80, 0x00,0xff,0xff,0x00, 0x00,0x7f,0xfe,0x00, 0x00,0x3f,0xfc,0x00, 0x00,0x1f,0xf8,0x00, 0x00,0x0f,0xf0,0x00, 0x00,0x07,0xe0,0x00, 0x00,0x03,0xc0,0x00,

0x00,0x01,0x80,0x00 };

glEnable(GL_POLYGON_STIPPLE); // 启动多边形填充模式 glPolygonStipple(pattern); // 指定填充位图数组

glPolygonMode(GL_BACK,GL_FILL); // 设置正面填充模式 glPolygonMode(GL_FRONT,GL_POINT); // 设置反面填充模式 glBegin(GL_POLYGON);

glColor3f(1.0f,1.0f,1.0f); glVertex3f(-0.3f,0.5f,0.0f); glVertex3f(0.3f,0.5f,0.0f); glVertex3f(0.5f,0.0f,0.0f); glVertex3f(0.3f,-0.5f,0.0f); glVertex3f(-0.3f,-0.5f,0.0f); glVertex3f(-0.5f,0.0f,0.0f); glEnd();

glDisable(GL_POLYGON_STIPPLE);

glFlush(); }

int main(int argc, char *argv[]) { glutInit(&argc, argv);

glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE); glutInitWindowPosition(100,100); glutInitWindowSize(400,400);

glutCreateWindow(\基本图元:多边形\glutDisplayFunc(&drawPolygon); glutMainLoop(); return 0; }

编译运行,效果如图所示:

由于多边形的反面我们看不到,所以也看不到它的填充模式。 画三角形

画三角形,需要调用: glEnable(GL_TRIANGLES); 来启动。

在glEnable(GL_TRIANGLES)与glEnd()之间的点,按照顺序,每三个点对应一个三角形。例如

void drawTriangles(void) { glClear(GL_COLOR_BUFFER_BIT); glBegin(GL_TRIANGLES); glColor3f(1.0f,1.0f,0.0f); glVertex3f(-0.3f,0.5f,0.0f); glVertex3f(0.3f,0.5f,0.0f); glVertex3f(0.5f,0.0f,0.0f);

glColor3f(0.0f,1.0f,1.0f); glVertex3f(0.3f,-0.5f,0.0f); glVertex3f(-0.3f,-0.5f,0.0f); glVertex3f(-0.5f,0.0f,0.0f); glEnd();

glFlush(); }

编译运行,效果如图所示:

画其它图形

还可以方便地画出其它图形,可以参考前面的表格和图形示例。

2、

glBegin()用法小结

openGL 2009-10-09 17:19:19 阅读517 评论0 字号:大中小

1.在glBegin()和glEnd()之间可调用的函数 函数 函数意义

glVertex*() 设置顶点坐标 glColor*() 设置当前颜色 glIndex*() 设置当前颜色表 glNormal*() 设置法向坐标 glEvalCoord*() 产生坐标

glCallList(),glCallLists() 执行显示列表 glTexCoord*() 设置纹理坐标 glEdgeFlag*() 控制边界绘制 glMaterial*() 设置材质

表7-2 在glBegin()和glEnd()之间可调用的函数

glVertex3f()表示了该函数属于 gl库,参数是三个float型参数指针。我们用glVertex*()来表示这一类函数。

基本库

2.几何图元类型和说明 类型 说明

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 连续填充四边形串 表7-1 几何图元类型和说明

3、

OpenGL常见函数功能查询

一:GL库函数 使用颜色

glshadeModel--选择平面明暗模式或光滑明暗模式 glColor--设置当前颜色

glColorPointer--定义颜色数组 gllndex--设置当前颜色索引

gllndexPointer--定义颜色索引数组

glCOforTableEXT--为目标调色板纹理指定调色板的格式和大小 glColorsubTableEXT--指定需要替代的目标纹理调色板的一部分

绘制几何图原及物体 glVertex--指定顶点

glVertexPointer--定义顶点数据数组

glArrayElement--指定用来绘制顶点的数组元素 glBegin,glEnd--限定一个或多个图原顶点的绘制 glEdgeFlag,glEdgeFlagy--指定边界标记 glPointsize--指定光栅化点的直径 glLinewidth--指定光栅化直线的宽度 glLinestipple--指定点划线

glPolygonMode--选择多边形光栅化模式

glFrontFace--定义正面多边形和反反面多边形 glPolygonstipple--设置多边形点划图 glDrawElements--从数组数据绘制图原 glRect--绘制矩形 坐标转换

glTranslate--用平移矩阵乘以当前矩阵 glRotate--用旋转矩阵乘以当前矩阵 glscale--用缩放矩阵乘以当前矩阵 glViewport--设置机口

glFrustum--用透视矩阵乘以当前矩阵 glorthO--用正视矩阵乘以当前矩阵

glClipPlane--指定切割几何物体的平面 堆栈操作

glLoadMatrix--用任意矩阵替换当前矩阵 glMultMatrix--用任意矩阵乘以当前矩阵 glMatrixMode--指定哪一个矩阵是当前矩阵

glPushMatrix,glPopMatrix--压人和弹出当前矩阵堆栈 glPushAttrib,glPopAttrib--压人和弹出属性堆栈

glPushClientAttrib,glPopClientAttrib--在客户属性堆栈中保存和恢复客户状态变量组

glPushName,gPopName--压人和弹出名称堆栈 gllnitNames--初始名称堆栈

glLoadName--向名称堆栈中装载名称 显示列表

glNewList,glEndList--创建或替换一个显示列表 glCallLISt--执行一个显示列表 glCallLISts--执行一列显示列表

glGenLists--生成一组空的相邻的显示列表 glDeleteLists--删除一组相邻的显示列表 gllSLISt--检验显示列表的存在 使用光照和材质

glNormal--设置当前的法向量

glNormalPointer--定义法向量数组 glLight--设置光源参数

glLightModel--设置光照模型参数

glMaterial--为光照模型指定材质参数

glColorMateria--使材质颜色跟踪当前颜色 像素操作

glRasterPos--为像素操作指定光栅位置 glBitmap--绘制位图

glReadPixels--从帧缓存中读取一块像素 glDrawPixels--将一个像素块写人帧缓存 glCopyPixels--在帧缓存中拷贝像素

glCopyTexlmage1D--将像素从帧缓存拷贝到一维纹理图像中 glCopyTexlmageZD--把像素从帧缓存拷贝到二维纹理图像中 glCopyTexsublmagelD--从帧缓存中拷贝一维纹理图像的子图像 glCopyTexsublmageZD--从帧缓存中拷贝二维纹理图像的子图像 glPixelZoom--指定像素缩放因子 glPixelstore--设置像素存储模式 glPixelTransfer--设置像素传输模式 glPixelMap--设置像素传输映射表 纹理映射

glTexlmagelD--指定一维纹理图像 glTexlmageZD--指定二维纹理映射 glTexParameter--设置纹理参数

glTexsublmage1D--指定已存在的一维纹理图像的一部分 glTexsublmageZD--指定已存在的二维纹理图像的一部分 glTexEnv--设置纹理环境参数 glTexCoord--设置当前纹理坐标 glTexGen--控制纹理坐标的生成

glTexCoordPointer--定义纹理坐标数组 glDeleteTextures--删除命名的纹理 特殊效果操作

glBlendFunc--指定像素的数学算法 glHint--指定由实现确定的控制行为 glFOg--指定雾化参数 帧缓存操作

glClear--将缓存清除为预先的设置值 glClearAccum--设置累加缓存的清除值 glClearColor--设置颜色缓存的清除值 glClearDepth--设置深度缓存的清除值

glClearlndex--设置颜色索引缓存的清除值 glClearstencil--设置模板缓存的清除值 glDrawBuffer--指定绘制的颜色缓存

gllndexMask--控制颜色索引缓存中单个位的写操作 glColorMask--激活或关闭帧缓存颜色分量的写操作 glDepthMask--激活或关闭对深度缓存的写操作 glstencilMask--控制模板平面中单个位的写操作

glAlphaFunc-一指定alpha检验函数

glstencilFunc--设置模板检验函数和参考值 glstencilop--设置模板检验操作

glDepthFunc--指定深度比较中使用的数值

glDepthRange--指定从单位化的设备坐标到窗口坐标的z值映射 glLOgiCOp--为颜色索引绘制指定逻辑像素操作 glACCum--对累加缓存进行操作 绘制曲线和曲面

glEvalCoord--求取激活的一维和二维纹理图 glMapl--定义一维求值器 glMapZ--定义二维求值器

glMapGrid--定义一维或二维网格

glEvalMesh--计算一维或二维点网格或线网格 glEvalPoint--生成并求取网格中的单个点 查询函数

glGet--返回所选择的参数值

glGetClipPlane--返回指定的切平面系数

glGetColorTableEXT--获得当前目标纹理调色板的颜色表数据

glGetColorTableParameterfvEXT,glGetColorTableParameterlvEXT-从颜色表中获得调色板参数

glGetError--返回错误信息 glGetLight--返回光源参数值 glGetMap--返回求值器参数 glGetMaterial--返回材质参数

glGetPixelMap--返回指定的像素映像 glGetPointery--返回顶点数据数组地J glGetPolygonstipple--返回多边形点戈 glGetstring--返回描述当前OpenGL glGetTexEnv--返回纹理环境参数

glGetTexGen--返回纹理坐标生成参数 glGetTexlmage--返回纹理图像

glGetTexLevelParameter--返回指定细节水平的纹理参数值 glGetTexParameter--返回纹理参数值

二:GLU库函数

绘制NURBS曲线和曲面

gluNewNurbsRenderer--创建一个NURBS对像 gluNurbsProperty--设置NURBS属性

gluNurbsCallback--为NURBS对像定义回调函数

gluBeginCurve,gluEndCurve--限定NURBS曲线的定义 gluNurbsCurve--定义NURBS曲线的形状 gluDeleteNurbsRenderer--删除NURBS对像

gluBeglnsurface,gluEndsurface--限定NURBS曲面的定义

ghiNurbssurface--定义NURBS曲面的形状

gluBeginTrim,gluEndTrim--限定NURBS裁剪环的定义 gluPwlCurve--描述分段线性NURBS裁剪曲线

gfuBeglnPolygon, gluEndPolygon--限定多边形的定义 gluPickMatrix--定义拾取区域 绘制二次几何物体

gluNewQuadric--创建一个二次对象

gluQuadricDrawsope--指定二次对象的绘制方式

gluQuadricNormals--指定二次对象使用的法向量类型

gluQuadricorientation--指定二次对象的内侧面或外侧面方向 gluCylinder--绘制圆柱体 ghisphere--绘制球体 glllDISk--绘制圆盘

gluPartialDisk--绘制部分圆盘 gliJDeleteQuadric--删除二次对象

gluQuadricTexture--指定是否为二次对象使用纹理 ghiQuadricCallback--为二次对象定义回调 网格化

gluNewTess--创建一个网格化对象 gluTessVertex--在多边形上指定顶点

gluTessCallback--为网格化对象定义回调

gluTessBeglnPolygon,ghiTessEndPolygon--限定多边形的描述

gluTessBeglnContour,gluTessEndContour--限定多边形轮廓线的定义 gluTessProperty--设置网格化对象的属性 ghiNextContour--标记开始绘制另一个轮廓线 gluTessNormal--为多边形指定法向量 gluDeleteTess--删除网格化对象 坐标变换

gluOorthoZD--定义二维正视投影矩阵 gluPerspective--创建透视投影矩阵 gltlLOOkAt--定义视景转换

gluProject--将物体坐标映射为窗口坐标 gluInProject--将窗口坐标映射力物体坐标 多重映射

gfuBuildlDMipmaps--创建一维多重映射 gluBuildZDMipmaps--创建H维多重映射 gluSCalelmage--将图像缩放到任意尺寸 查询函数

ghiErrorstring--从OpenGL或GLU错误代码中生成错误字符串 gluGetNurbsProperty--获得NURBS属性

ghiGetstring--获得描述GLU版本号或支持GLU扩展调用的字符串 ghiGetTessProperty--获得网格化对象的属性

三:GLUT库函数

初始化和启动事件处理 ghjtlnit--初始化GLUT库

glutlnitwindowPosition--设置初始窗口位置 glutlnitwindowsize--设置初始窗口大小 glutlnitDisplayMode--设置初始显示模式 glutMainLoop--进人GLUT事件处理循环 窗口管理

glutCreatewindow--创建顶层窗口 glutCreatesubwindow--创建子窗口

ghitHidewindow--隐藏当前窗口的显示状态

glutshowwindow--改变当前窗口的显示状态,使其显示 gfutsetwindowTitle--设置当前顶层窗口的窗口标题 ghitsetlconTitle--设置当前顶层窗口的图标标题 ghitPostRedisplay--标记当前窗口需要重新绘制 glutswapBuffers--交换当前窗口的缓存 glutFullscreen--关闭全屏显示

glutPositionwindow--申请改变当前窗口的位置 gintReshapewindow--申请改变当前窗口的大小 glutsetwindow--设置当前窗口

ghitGetwindow--获得当前窗口的标识符

glutPopwindow--改变当前窗口的位置,使其前移 ghitPtshwilldOO--改变当前窗口的位置,使其后移 glutDestroywindow--销毁指定的窗口

glutlconifywindow--使当前窗口图标化显示 glutsetCursor--设置当前窗口的鼠标形状 重叠层管理

glutEstablishoverlay--创建当前窗口的重叠层 glutUseLayer--改变当前窗口的使用层

glutRemoveoverlay--删除当前窗口的重叠层

glutPostoverlayRedisplay--标记当前窗口的重叠层 需要重新绘制

glutshowoverlay--显示当前窗口的重叠层 glutHideoverlay--显示当前窗口的重叠层 菜单管理

glutCreateMenu--创建一个新的弹出式菜单

glutAddMenuEntry--在当前菜单的底部增加一个菜单条目

glutAddsubMenu--在当前菜单的底部增加一个子菜单触发条目

glutAttachMenu--把当前窗口的一个鼠标按键与当前菜单的标识符联系起来 glutGetMenu--获取当前菜单的标识符 glutsetMenu--设置当前菜单

glutDestroyMenu--删除指定的菜单

glutChangeToMenuEntry--将指定的当前菜单中的菜单项更改为菜单条目

glutChangeTosubMenu--将指定的当前菜单中的菜单项更改为子菜单触发条目 glutRemoveMenultem--删除指定的菜单项

glutDetachMenu--释放当前窗口的一个鼠标按键 注册国调函数

glutDispfayFunc--注册当前窗口的显示回调函数

glutReshapeFunc--注册当前窗口的形状变化回调函数 glutMouseFunc--注册当前窗口的鼠标回调函数 glutMotionFunc--设置移动回调函数

glutldleFunc--设置全局的空闲回调函数

glutVisibilityFunc--设置当前窗口的可视回调函数 glutKeyboardFunc--注册当前窗口的键盘回调函数 glutspecialFunc--设置当前窗口的特定键回调函数

glutoverlayDisplayFunc--注册当前窗口的重叠层显示回调函数 glutPassiveMotionFunc--设置当前窗口的被动移动回调函数 glutEntryFunc--设置当前窗口的鼠标进出回调函数

glutspaceballMotionFunc--设置当前窗口的空间球移动回调函数 glutspaceballRotateFunc--设置当前窗口的空间球旋转回调函数 glutspaceballButtonFunc--设置当前窗口的空间球按键回调函数 glutButtonBoxFunc--设置当前窗口的拨号按键盒按键回调函数 glutDialsFunc--设置当前窗口的拨号按键盒拨号回调函数 glutTabletMotionFunc--设置图形板移动回调函数

glutTabletButtonFunc--设置当前窗口的图形板按键回调函数 glutMenustatusFunc--设置全局的菜单状态回调函数

glutTimerFunc--注册按一定时间间隔触发的定时器回调函数 颜色素引映射表管理

glutsetColor--设置当前窗口当前层一个颜色表单元的颜色 glutGetColor--获得指定的索引颜色

glutCopyColormap--将逻辑颜色表从指定的窗口拷贝到当前窗口 状态检索

glutGet--检索指定的GLUT状态

glutLayerGet--检索属于当前窗口重叠层的 GLU T状态 glutDeviceGet--检索GLUT设备信息

glutGetModifiers--返回修饰键在引起某些回调的事件发生时的状态

glutExtensionsupported--判别当前OpenGL版本是否支持给定的OpenGL扩展 字体绘制

glutBltmapCharcter--绘制一个位图字符 glutBitmapwidth--返回一个位图字符的宽度 glutstrokeCharcter--绘制一个笔画字符 glutstrokewidth--返回一个笔画字体的宽度 几何图形绘制

glutSolidsphere,glutwiresphere--绘制实心球体和线框球体 glutsolidCube,glutwireCube--绘制实心立方体和线框立方体 glutsolidCone,glutwireCone--绘制实心圆锥体和线框圆锥体

glutsolidTorus,glutwireTorus--绘制实心圆环和线框圆环 glutSolidDOdeCahedroll,glLltwiFeDOdechedfotl--绘制实心 十二面体和线框十二面体

glutSolidOctahedron,glutWireOctahedron--绘制买心八面体和线框八面体 glutsolldTetrahedron,glutwireTetrahedron--绘制实心四面体和线框四面体 glutSollelcosahedron,glutwirelcosahedron--绘制实心二十面体和线框二十面体

glutsolidTeapot,glutwireTeapot--绘制实心茶壶和线框茶壶

4、

如何描绘空间上的一个物体,在图形学上有很多方法,OpenGL通过将物体抽象为笛卡尔坐标系下点、线段、多边形的集合,再将点、线段、多边形等通过在函数glBegin()与glEnd()之间的一系列顶点数据,绘制出图形还原物体。 OpenGL通过glBegin()与glEnd()函数完成点、线、三角形、四边形及多边形的绘制,glBegin(GLenum)函数原型如下: Cpp代码

1. glBegin(GLenum)| 2. ... 3. glEnd()

参数GLenum有以下10个参数: GL_POINTS:表示将要绘制点 GL_LINES:表示函数开始绘制线

GL_LINE_STRIP:表示函数将开始绘制折线 GL_LINE_LOOP:表示函数将开始绘制闭合曲线 GL_TRIANLES:表示函数开始绘制三角形

GL_TRIANLE_STRIP:表示函数将开始绘制三角形片 GL_TRIANLE_FAN:表示函数将开始绘制三角形扇 GL_QUADS:表示函数开始绘制四边形

GL_QUAD_STRIP:表示函数开始绘制多边形片 GL_POLYGON:表示函数绘制多边形 1、绘制二维的点:

Cpp代码

1. glBegin(GL_POINTS); 2. glVertex2f(0.0f,0.0f); 3. glEnd();

在初始化OPENGL运行环境后,如上代码,将绘制一个2维的点,点的坐标为(0,0),OpenGL中绘制的二维的点实际和三维点一样,不过二维的点是将笛卡尔坐标的z轴定位在原点,二维点的坐标也就是(x,y,0) 2、绘制线:

Java代码

1. glBegin(GL_LINES);

2. glVertex2f(0.0f,0.0f); 3. glVertex2f(0.01f,-0.4f); 4. glEnd();

OpenGL的任何图形都是基于点,如上绘制2个点,链接成一个直线,当然绘制以后可能出现锯齿,这样就需要进行一下反走向处理。 GL_LINES:绘制两条线段 GL_LINE_STRIP:绘制连续折线 GL_LINE_LOOP:绘制闭合曲线

3种绘制方式会产生不同的效果,具体在vc环境下测试即可看见。 3、绘制面 绘制三角形:

Cpp代码

1. glBegin(GL_TRIANGLES);

2. glVertex3f(0.0f,0.0f,0.0f); 3. glVertex3f(1.0f,0.0f,0.0f); 4. glVertex3f(0.0f,1.0f,0.0f); 5. glEnd();

如上的代码将会在笛卡尔坐标中根据三个点绘制一个三角形,三角形的三个点坐标分别为(0,0,0)、(1,0,0)、(0,1,0)

5、

绘制多边形的基本语句 openGL

(2008-09-26 10:57:54)

转载

标签:

分类:c#web~数据库

it

来至:http://hi.http://www.wodefanwen.com//limeng_hoho/blog/category/Opengl 本文介绍绘制多边形的基本语句。

OpenGL提供了描述点、线、多边形的机制。它们通过glBegin()和glEnd()的配对

来完成。glBegin()有一个GLenum的参数,它可以为如下10个常量:

GL_POINTS,GL_LINES,GL_LINE_STRIP(折线),

GL_LINE_LOOP(封闭线),GL_TIANGLES,

GL_TRIANGLE_STRIP(连续画三角),GL_TRIANGLE_FAN(三角形扇),

GL_QUADS,GL_QUAD_STRIP,GL_POLYGON

当glBegin()函数的参数为GL_POINTs时,表示在glBegin()和glEnd()函数对之间将

绘制点。如:

glBegin(GL_POINTS)

glVertex2f(0.0f,0.0f);//定义二维点

glVertex3f(0.1f,0.2f,0.3f);//定义三维点 glEnd();

为了获取被设备支持的点的大小的范围,OpenGL提供了glGet()函数,采用如下语句获

得点的大小范围。

GLfloat fPointSize[2];

glGetFloatv(GL_POINT_SIZE_RANGE,fPointSize);

glGetFloat()函数的第一个参数必须是OpenGL常量,第二个参数是数组的地址。函数按第一个参数的指示向第二个参数所指地址传输数据,fPointSize[0]存储点的大小的最小值,fPointSize[1]存储点的大小的最大值。

(1)采用如下语句获取当前点的大小

GLfloat fCurrentPointSize;

glGetFloatv(GL_POINT_SIZE,&fCurrentPointSize)

(2)将glBegin()函数的参数设为GL_Lines,便可以用glBegin()/glEnd()函数lai绘制直线。如:

glBegin(GL_LINES)

glVertex2f(0.4f,0.4f);

glVertex2f(0.0f,-0.4f);

glEnd();

通过glLineWidth()来自定义线的宽度,如:glLineWidth(2.0f)申明了两个像素作为线的宽度

(3)通过如下语句确定线的宽度:

GLfloat fLineWidth[2];

glGetFloatv(GL_LINE_WIDTH_RANGE,fLineWidth);

fLineWidth中存放线宽的最小值和最大值。

(4)OpenGL通过glLineStipple()函数来获取所定义的线型。

(5)为了使所获取的线型被OpenGL支持,必须事先启动改变线型的机制

glEnable(GL_LINE_STIPPLE);

当不再使用自定义的线型时,应将功能关闭

glDisable(GL_LINE_STIPPLE);

(6)在OpenGL中,glEnable()是一个重要的函数,通过该函数可以启动OpenGL的许多特定功能。

(7)glBegin()函数的参数为GL_LINE_LOOP时在glBegin()和glEnd()之间绘制闭合折线。

glBegin(GL_LINE_LOOP)

glVetex2f(-0.3f,0.0f);

glVetex2f(0.8f,0.0f);

glVetex3f(0.0f,0.8f);

glEnd();

此处折线的闭合由函数完成,最后一个点不必是第一个点。

(8)在OpenGL中,一个多边形至少有3个顶点。直线不能相交,多边形应构成单连通

的凸区域。一个多边形有前面和后面之分,前面和后面可以有不同的属性。

(9)一个多边形的前面和后面是需要指定的,可以通过其顶点的顺序来确定,缺省的逆

时针排列的顶点定义的多边形是前面的。

(10)OpenGL提供函数glFrontFace()来指定多边形的前面。函数参数只能为GL_CW或

GL_CCW,

GL_CW表示按顺时针定义的多边形是前面的,

GL_CCW表示按逆时针定义的多边形是前面的。

(11)OpenGL允许用户采用一个32*32的位图对多边形进行填充。

(12)位图可以用如下结构定义:

Glubyte polygonFillPattern[]={ };

(13)一旦完成模式的自定义,就可以用glEnable(GL_POLYGON_STIPPLE)通知OpenGLdui改变了的填充模式进行响应。

(14)如果要回到通常的填充模式,只需用用glDisable(GL_POLYGON_STIPPLE)终止自定义的填充模式。

(15)应用多边形填充模式,可以进行半透明处理,淡入淡出效果处理等。

(16)用GL_TRIANGELS来完成三角形的绘制。

glBegin(GL_TRIANGLES)

glVertex2f(-0.5f,0.4f);

glVertex2f(-0.6f,-0.5f);

glVertex2f(0.5f,-0.5f);

glEnd();

(17)当glBegin()的参数为GL_TRIANGLE_STRIP时,可以画一系列的三角形,称其为三角形片。在glBegin()/glEnd()函数对中,采用顶点描述三角形时,前三个顶点描述了第一个三角形,之后每加入一个顶点就延伸出一个三角形,第二个三角形由第二三四三个顶点构成。

(18)在OpenGL中,可以用多个三角形构成三角形扇,glBegin()/glEnd()函数对的前三个顶点定义了第一个三角形,自后每增加一个顶点就增加一个三角形,由第一个顶点作为扇心。

(19)应用GL_QUADS参数可以画一组四边形,绘制时要注意四边形顶点的排列顺序。

(20)应用参数GL_QUAD_STRIP,在glBegin()/glEnd()函数对中,前四个顶点定义第一个四边形,之后每加入两个顶点就加入一个四边形。

(21)要绘制如图所示的凹多边形,可用通过绘制两个组合的四边形,但是会产生一条本不存在的边3-4,因而需要对这条边加以隐藏。

(22)OpenGL通过glEdgeFlag()函数来说明边的可见性。该函数位于两个glVertex()函数之间,说明由这两点构成的边的可见性。参数为TRUE可见,FALSE不可见。

(23)一旦确定了glEdgeFlag()函数的参数,此后所绘制的边的可见性就不会发生改变,除非再次调用glEdgeFlag()函数。

(25)一个物体无论其表面形状多么复杂,计算机都将它视为由若干个小面组成的,通常小面采用三角形或四边形。

首先对曲面进行网格划分,称有限单元化;其次要获得网格的各个顶点坐标,并对顶点进行数学描述形成单个面,通过面循环构成整个物体的拓扑结构;对顶点赋予颜色、纹理、法线等信息;最后将以上操作的结果作为输入信息传递给OpenGL。

6、

第37课

卡通映射:

什么是卡通了,一个轮廓加上少量的几种颜色。使用一维纹理映射,你也可以实现这种效果。

看到人们仍然e-mail我请求在文章中使用我方才在GameDev.net上写的源代码,还看到文章的第二版(在那每一个API附带源码)不是在中途完成之前连贯的结束。我已经把这篇指南一并出租给了NeHe(这实际上是写文章的最初意图)因此你们所有的 OpenGL领袖可以玩转它。对模型的选择表示抱歉,但是我最近一直在玩Quake 2。 注释:这篇文章的源代码可以在这里找到:

http://www.gamedev.net/reference/programming/features/celshading.

这篇指南实际上并不解释原理,仅仅解释代码。在上面的连接中可以发现为什么它能工作。现在不断地大声抱怨STOP E-MAILING ME REQUESTS FOR SOURCE CODE!!!!

首先,我们需要包含一些额外的头文件。第一个(math.h)我们可以使用sqrtf (square root)函数,第二个用来访问文件。

#include #include

现在我们将定义一些结构体来帮助我们存贮我们的数据(保存好几百浮点数组)。第一个是tagMATRIX结构体。如果你仔细地看,你将看到我们正象包含一个十六个浮点数的1维数组~一个2维4×4数族一样存储

那个矩阵。这下至OpenGL存储它的矩阵的方式。如果我们使用4x4数组,这些值将发生错误的顺序。

typedef struct tagMATRIX OpenGL矩阵的结构体 { float Data[16]; 矩阵的格式我们使用[16 }

MATRIX;

// 保存

// 由于OpenGL的

第二是向量的类。 仅存储X,Y和Z的值

typedef struct tagVECTOR 一个单精度向量的结构体 { float X, Y, Z; }

VECTOR;

// 存储

// 向量的分量

第三,我们持有顶点的结构。每一个顶点仅需要它的法线和位置(没有纹理的现行纵坐标)信息。它们必须以这样的次序被存放,否则当它停

止装载文件的事件将发生严重的错误(我发现艰难的情形:(教我分块

出租我的代码。)。

typedef struct tagVERTEX 单一顶点的结构 { VECTOR Nor; VECTOR Pos; }

VERTEX;

// 存放

// 顶点法线 // 顶点位置

最后是多边形的结构。我知道这是存储顶点的愚蠢的方法,要不是它完美工作的简单的缘故。通常我愿意使用一个顶点数组,一个多边形数组, 和包括一个在多边形中的3个顶点的指数,但这比较容易显示你想干什么。

typedef struct tagPOLYGON 单一多边形的结构 { VERTEX Verts[3]; 点结构数组 }

POLYGON;

// 存储

// 3个顶

优美简单的材料也在这里了。为每一个变量的一个解释考虑那个注释。

bool outlineDraw = true; 轮廓的标记 bool outlineSmooth = false; // Anti-Alias 线段的标记 float outlineColor[3] = { 0.0f, 0.0f, 0.0f }; // 线段的颜色 float outlineWidth = 3.0f; 的宽度

VECTOR lightAngle; 的方向 bool lightRotate = false; // 是否我们旋转灯光的标记

// 绘制

// 线段

// 灯光

float modelAngle = 0.0f; 的Y轴角度 bool modelRotate = false;

POLYGON *polyData = NULL; // 多边形数据 int polyNum = 0; 形的编号

GLuint shaderTexture[1]; // 存储纹理ID

// 模型

// 旋转模

// 多边

这是得到的再简单不过的模型文件格式。 最初的少量字节存储在场景中的多边形的编号,文件的其余是tagPOLYGON结构体的一个数组。正

因如此,数据在没有任何需要去分类到详细的顺序的情况下被读出。

BOOL ReadMesh () // 读“model.txt” 文件 { FILE *In = fopen (\ // 打开文件 if (!In) return FALSE; // 如果文件没有打开返回 FALSE fread (&polyNum, sizeof (int), 1, In); // 读文件头,多边形的个数 polyData = new POLYGON [polyNum]; // 分配内存 fread (&polyData[0], sizeof (POLYGON) * polyNum, 1, In);// 把所有多边形的数据读入 fclose (In); // 关闭文件 return TRUE; // 工作完成 }

一些基本的数学函数而已。DotProduct计算2个向量或平面之间的角,Magnitude函数计算向量的长度,Normalize函数缩放向量到一个单位

长度。

inline float DotProduct (VECTOR &V1, VECTOR &V2) //计算两个向量之间的角度 { return V1.X * V2.X + V1.Y * V2.Y + V1.Z * V2.Z; }

inline float Magnitude (VECTOR &V) // 计算向量的长度 { return sqrtf (V.X * V.X + V.Y * V.Y + V.Z * V.Z); }

void Normalize (VECTOR &V) // 创建一个单位长度的向量 { float M = Magnitude (V); if (M != 0.0f) // 确保我们没有被0隔开 { V.X /= M; V.Y /= M; V.Z /= M; } }

这个函数利用给定的矩阵旋转一个向量。请注意它仅旋转这个向量——与向量的位置相比它算不了什么。它用来当旋转法线确保当我们在计算

灯光时它们停留在正确的方向上。

void RotateVector (MATRIX &M, VECTOR &V, VECTOR &D) // 利用提供的矩阵旋转一个向量 { D.X = (M.Data[0] * V.X) + (M.Data[4] * V.Y) + (M.Data[8] * V.Z); D.Y = (M.Data[1] * V.X) + (M.Data[5] * V.Y) + (M.Data[9] * V.Z);

}

D.Z = (M.Data[2] * V.X) + (M.Data[6] * V.Y) + (M.Data[10] * V.Z);

引擎的第一个主要的函数?? 初始化,按所说的精确地做。我已经砍 掉了在注释中不再需要的代码段。

// 一些GL 初始代码和用户初始化从这里开始

BOOL Initialize (GL_Window* window, Keys* keys) {

这3个变量用来装载着色文件。在文本文件中为了单一的线段线段包含了空间,虽然shaderData存储了真实的着色值。你可能奇怪为什么我们的96个值被32个代替了。好了,我们需要转换greyscale 值为RGB

以便OpenGL能使用它们。我们仍然可以以greyscale存储这些值,但向上负载纹理时我们至于R,G和B成分仅仅使用同一值。

char Line[255]; 字符的存储量 float shaderData[32][3]; // 96个着色值的存储量 g_window = window; g_keys = keys; FILE *In = NULL; // 文件指针

// 255个

当绘制线条时,我们想要确保很平滑。初值被关闭,但是按“2”键, 它可以被toggled on/off。

glShadeModel (GL_SMOOTH); // 使用色彩阴影平滑 glDisable (GL_LINE_SMOOTH); // 线条平滑初始化不可用 glHint (GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // 提高计算精度 glClearColor (0.7f, 0.7f, 0.7f, 0.0f); // 设置为灰色背景

glClearDepth (1.0f); 值 glEnable (GL_DEPTH_TEST); glDepthFunc (GL_LESS); glShadeModel (GL_SMOOTH); glDisable (GL_LINE_SMOOTH); glEnable (GL_CULL_FACE); 形功能

// 设置深度缓存

// 启用深度测试

// 设置深度比较函数 // 启用反走样

// 启用剔除多边

我们使 OpenGL灯光不可用因为我们自己做所以的灯光计算。

glDisable (GL_LIGHTING); OpenGL 灯光不可用

// 使

这里是我们装载阴影文件的地方。它简单地以32个浮点值ASCII码存 放(为了轻松修改),每一个在separate线上。

In = fopen (\阴影文件 if (In) 文件是否打开 { for (i = 0; i < 32; i++) // 循环32次 { if (feof (In)) 文件是否结束 break; fgets (Line, 255, In); 当前线条

// 打开

// 检查

// 检查

// 获得

这里我们转换 greyscale 值为 RGB, 正象上面所描述的。

// 从头到尾复制这个值

shaderData[i][0] = shaderData[i][1] = shaderData[i][2] = atof (Line); } fclose (In); // 关闭文件 } else return FALSE;

现在我们向上装载这个纹理。同样它清楚地规定,不要使用任何一种过滤在纹理上否则它看起来奇怪,至少可以这样说。GL_TEXTURE_1D被使

用因为它是值的一维数组。

glGenTextures (1, &shaderTexture[0]); // 获得一个自由的纹理ID glBindTexture (GL_TEXTURE_1D, shaderTexture[0]); // 绑定这个纹理。 从现在开始它变为一维 // 使用邻近点过滤 glTexParameteri (GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri (GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); // 设置纹理 glTexImage1D (GL_TEXTURE_1D, 0, GL_RGB, 32, 0, GL_RGB , GL_FLOAT, shaderData);

现在调整灯光方向。我已经使得它向下指向Z轴正方向,这意味着它将 正面碰撞模型

lightAngle.X = 0.0f; lightAngle.Y = 0.0f; lightAngle.Z = 1.0f; Normalize (lightAngle);

读取Mesh文件,并返回

return ReadMesh (); Mesh文件,并返回 }

// 读取

与上面的函数相对应?? 卸载,删除由Initalize 和 ReadMesh 创建 的纹理和多边形数据。

void Deinitialize (void) { glDeleteTextures (1, &shaderTexture[0]); 阴影纹理 delete [] polyData; 据 }

// 删除

// 删除多边形数

主要的演示循环。所有这些用来处理输入和更新角度。控制如下: =锁定旋转

1 = 锁定轮廓绘制

2 = 锁定轮廓 anti-aliasing =增加线宽 = 减小线宽

void Update (DWORD milliseconds) 执行动作更新 { if (g_keys->keyDown [' '] == TRUE) 是否被按下 { modelRotate = !modelRotate; 模型旋转开/关

// 这里

// 空格

// 锁定

g_keys->keyDown [' '] = FALSE; } if (g_keys->keyDown ['1'] == TRUE) // 1是否被按下 { outlineDraw = !outlineDraw; // 切换是否绘制轮廓线 g_keys->keyDown ['1'] = FALSE; } if (g_keys->keyDown ['2'] == TRUE) // 2是否被按下 { outlineSmooth = !outlineSmooth; // 切换是否使用反走样 g_keys->keyDown ['2'] = FALSE; } if (g_keys->keyDown [VK_UP] == TRUE) // 上键增加线的宽度 { outlineWidth++; g_keys->keyDown [VK_UP] = FALSE; } if (g_keys->keyDown [VK_DOWN] == TRUE) // 下减少线的宽度 { outlineWidth--; g_keys->keyDown [VK_DOWN] = FALSE; } if (modelRotate) // 是否旋转 modelAngle += (float) (milliseconds) / 10.0f; // 更新旋转角度 }

你一直在等待的函数。Draw 函数做每一件事情——计算阴影的值,着 色网孔,着色轮廓,等等,这是它作的。

void Draw (void) {

TmpShade用来存储当前顶点的色度值。所有顶点数据同时被计算,意味着我们只需使用我们能继续使用的单个的变量。

TmpMatrix, TmpVector 和 TmpNormal同样被用来计算顶点数据,

TmpMatrix在函数开始时被调整一次并一直保持到Draw函数被再次调用。TmpVector 和 TmpNormal则相反,当另一个顶点被处理时改变。

float TmpShade; 色度值 MATRIX TmpMatrix; // 临时 MATRIX 结构体 VECTOR TmpVector, TmpNormal; VECTOR结构体

清除缓冲区矩阵数据

glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // 清除缓冲区 glLoadIdentity (); // 重置矩阵

首先检查我们是否想拥有平滑的轮廓。如果是,我们就打开 anti-alaising 。否则把它关闭。简单!

if (outlineSmooth) 我们是否想要 Anti-Aliased 线条 { glHint (GL_LINE_SMOOTH_HINT, GL_NICEST); 它们 glEnable (GL_LINE_SMOOTH);

// 检查

// 临时

// 临时

// 启用

} else

glDisable (GL_LINE_SMOOTH);

// 否则不启用

然后我们设置视口。我们反向移动摄象机2个单元,之后以一定角度旋转模型。注:由于我们首先移动摄象机,这个模型将在现场旋转。如果我们以另一种方法做,模型将绕摄象机旋转。

我们之后从OpenGL中取最新创建的矩阵并把它存储在 TmpMatrix。

glTranslatef (0.0f, 0.0f, -2.0f); 屏幕两个单位 glRotatef (modelAngle, 0.0f, 1.0f, 0.0f); 轴旋转这个模型 glGetFloatv (GL_MODELVIEW_MATRIX, TmpMatrix.Data); 产生的矩阵

// 移入// 绕Y

// 获得

戏法开始了。首先我们启用一维纹理,然后启用着色纹理。这被OpenGL用来当作一个look-up表格。我们之后调整模型的颜色(白色)我选择白色是因为它亮度高并且描影法比其它颜色好。我建议你不要使用黑

色:)

// 卡通渲染代码 glEnable (GL_TEXTURE_1D); 一维纹理 glBindTexture (GL_TEXTURE_1D, shaderTexture[0]); 我们的纹理 glColor3f (1.0f, 1.0f, 1.0f); 模型的颜色

// 启用// 锁定

// 调整

现在我们开始绘制那些三角形。尽管我们看到在数组中的每一个多边形,然后旋转它的每一个顶点。第一步是拷贝法线信息到一个临时的结

构中。因此我们能旋转法线,但仍然保留原来保存的值(没有精确降级)。

glBegin (GL_TRIANGLES); // 告诉 OpenGL 我们即将绘制三角形

for (i = 0; i < polyNum; i++) // 从头到尾循环每一个多边形 { for (j = 0; j < 3; j++) // 从头到尾循环每一个顶点 { TmpNormal.X =

polyData[i].Verts[j].Nor.X; // 用当前顶点的法线值填充TmpNormal结构 TmpNormal.Y = polyData[i].Verts[j].Nor.Y; TmpNormal.Z = polyData[i].Verts[j].Nor.Z;

第二,我们通过初期从OpenGL中攫取的矩阵来旋转这个法线。我们之 后规格化因此它并不全部变为螺旋形。

// 通过矩阵旋转 RotateVector (TmpMatrix, TmpNormal, TmpVector); Normalize (TmpVector); // 规格化这个新法线

第三,我们获得那个旋转的法线的点积灯光方向(称为lightAngle,因为我忘了从我的旧的light类中改变它)。我们之后约束这个值在 0——1的范围。(从-1到+1)

// 计算色度值 TmpShade = DotProduct (TmpVector, lightAngle); if (TmpShade < 0.0f) TmpShade = 0.0f; // 如果负值约束这个值到0

第四,对于OpenGL我们象忽略纹理坐标一样忽略这个值。阴影纹理与一个查找表一样来表现(色度值正成为指数),这是(我认为)为什么 纹理被创造主要原因。对于OpenGL我们之后忽略这个顶点位置,并1D 不断重复,重复。至此我认为你已经抓到了概念。

本文来源:https://www.bwwdw.com/article/mkfo.html

Top