Win32 OpenGL编程(3) 基本图元(点,直线,多边形)的绘制
write by 九天雁翎(JTianLing) -- blog.csdn.net/vagrxie
一、 提要
在前面两篇相关文章
《 Win32 OpenGL 编程(1)Win32下的OpenGL编程必须步骤》
《Win32 OpenGL编程(2) 寻找缺失的OpenGL函数》
中,我们已经建立了一个较为全面的Win32 OpenGL编程环境及一个简单的框架,并且,实际上掌握了OpenGL在Windows下与Win32窗口交互的方法,在此基础上,总算是可以正式进行一些OpenGL相关知识的学习,前面的那些也就算是热身。本文的目的是将OpenGL中基本图元(点,线,多边形)的绘制大概的讲解一遍,最后可以组合的使用这些技术用OpenGL完成较为复杂的2D图形。
二、 基本图元相关概念
首先讲讲相关的概念,在OpenGL中,即使是复杂的图形,实际上也是由一些非常基本的图元组成,即点,直线,多边形,多边形中用的较多的又是三角形和矩形。在数学中,两点确定一条直线,三点确定一个三角形和一个面,同一个面上的四个点确定一个四边形。。。。。。在OpenGL中也大致的利用此方式来确定直线和多边形,也就是说,当你想画一个直线或者一个多边形的时候,只需要告诉OpenGL能确定此直线或者多边形的点即可。用参考2中的描述是:“在OpenGL中,所有的几何物体最终都描述成一组有序的顶点”。有此基本的概念后就可以看下面的例子了。
三、 OpenGL的Hello World示例分析
这里的Hello World程序指的是一个利用OpenGL完成的矩形绘制程序,相对于在系列文章1中的Win32 OpenGL编程框架,简化了很多东西,只剩下最最基本的OpenGL元素,但也是一个完善的OpenGL示例了。此示例显示的是一个白色的矩形,运行效果如附图1,完整代码见我博客代码的2009-10-12/SimpleRectangle工程,具体下载及查看方法见本文最后的说明。
此示例OpenGL相关的主要就是两部分。
//OpenGL初始化开始
void SceneInit(int w,int h)
{
}
//这里进行所有的绘图工作
void SceneShow(GLvoid)
{
glClear(GL_COLOR_BUFFER_BIT);
glBegin(GL_QUADS);
glVertex3f(-0.5, -0.5, 0.0);
glVertex3f(0.5, -0.5, 0.0);
glVertex3f(0.5, 0.5, 0.0);
glVertex3f(-0.5, 0.5, 0.0);
glEnd();
glFlush();
}
我们下面从OpenGL的角度来分析此程序。作为HelloWorld级的程序,我简化了很多东西,首先OpenGL的初始化省略了,用的都是OpenGL的默认值,具体有哪些,后面一步一步说。以下是按步骤说明每个OpenGL函数。
1. glClear
OpenGL参考手册:
glClear takes a single argument that is the bitwise OR of several values indicating which buffer is to be cleared.
GL_COLOR_BUFFER_BIT Indicates the buffers currently enabled for color writing.
作用是清除颜色缓冲区。类似于我们使用一块新申请的内存时先用memset/ZeroMemory去清零一下,用这样的Clear操作为我们需要使用的颜色缓冲区(Color Buffer)清零一下。假如没有这样的操作,以前留在显存/内存(不确定)中的值会影响我们的操作,并且,这样的问题往往是非常难以调试和发现的,这一点大家可以尝试一下。
2. glBegin,glEnd
OpenGL参考手册:
glBegin, glEnd - delimit the vertices of a primitive or a group of like primitives
OpenGL代码的主体部分是:
glBegin(GL_QUADS);
glVertex3f(-0.5, -0.5, 0.0);
glVertex3f(0.5, -0.5, 0.0);
glVertex3f(0.5, 0.5, 0.0);
glVertex3f(-0.5, 0.5, 0.0);
glEnd();
glBegin与glEnd很明显是一对,标志着一组OpenGL操作的开始和结束。并且在参数中告诉了OpenGL下面的操作是针对什么图形进行的,此例中GL_QUADS是表示四边形。事实上还有很多其他的参数来表示各类图形,在《OpenGL Programming Guide》的此页中Figure 2-7 : Geometric Primitive Types 一图形象的说明了各个参数的作用。
3. glVertex*
glVertex3f就是在 基本图元相关概念 一节提到的OpenGL中确定顶点的函数。简而言之,上面的4句glVertex3f确定了矩形的4个顶点。(注意顺序)然后,OpenGL就会自动根据glBegin指定的参数去完成相关的绘制任务了,此例中GL_QUADS是表示四边形,所以最后的效果是一个矩形,实际的其他参数读者可以自己尝试一下。
4. OpenGL默认坐标系
我们再看一下glVertex*指定顶点的代码:
glVertex3f(-0.5, -0.5, 0.0);
glVertex3f(0.5, -0.5, 0.0);
glVertex3f(0.5, 0.5, 0.0);
glVertex3f(-0.5, 0.5, 0.0);
为什么上述就指定了一个矩形的四个顶点呢?需要说明的是,在OpenGL中默认坐标体系与Windows中常用的不同,Windows中常用的坐标体系(仅2D)是用户区的左上角为坐标原点,即(0.0,0.0)点,右为坐标轴的X轴正方向,下为Y轴正方向,OpenGL中的坐标轴(3D)默认以客户区中心点为坐标原点(0.0,0.0,0.0),右为坐标轴的X轴正方向,上为Y轴正方向,垂直指出屏幕的方向为Z轴正方向。长度定义是将客户区范围为按单位长度定义,即整个客户区恰好是(-1,-1)(左下)到(1,1)(右上)。附图2是一个上述示例程序附上OpenGL的平面坐标系的图,也可以作为OpenGL默认坐标系的参考图。
5. OpenGL函数命名
这里顺面介绍一下OpenGL函数的命名规范,因为C语言天生的弱点及丰富的数据类型,在OpenGL中凡是牵涉到与参数数量和数据类型相关的函数,一般的命名方式都是xxxx[n][t]。
xxxx表示函数的意义,[t]用于表示此函数对应的类型。一般用单个的字母表示参数的类型,s表示16位整数(OpenGL中将这个类型定义为GLshort),i表示32位整数(OpenGL中将这个类型定义为GLint和GLsizei),f表示32位浮点数(OpenGL中将这个类型定义为GLfloat),d表示64位浮点数(OpenGL中将这个类型定义为GLdouble)。此例中使用的是32位浮点数,所以是f。这是C语言没有函数重载机制的天生弱点导致的扭曲应对方案。(用C++就不需要这么麻烦了)
然后是数字,因为同样的原因,在C语言中一个同样意义的函数不能同时有不同个数的参数,所以OpenGL用一个数字来表示参数的个数,此例中是3,表示以3个参数(即点的X,Y,Z坐标)来表示顶点。(事实上还有glVertex2*,glVertex4*)
比如此例中,用如下代码效果是一样的:
glVertex2f(-0.5, -0.5);
glVertex2f(0.5, -0.5);
glVertex2f(0.5, 0.5) ;
glVertex2f(-0.5, 0.5);
在glVertex2f中,Z轴默认为0.
这里我依照参考2的用法,以*作为通配符来表示一组函数,*既可以表示代表参数数量的数字也可以表示代表类型的字母。
6. glFlush
OpenGL参考手册:
glFlush - force execution of GL commands in finite time
说白了就是强制执行已经指定的OpenGL命令,与fflush命名类似作用也类似。
7. 小结
以上的5个OpenGL函数就构成了一个基本的OpenGL程序(不包括模板中使用的那些),由glClear清空颜色缓冲区获得干净的环境,由glBegin指定开始一组顶点操作的开始,并确认绘制图形,由glVertex*指定顶点,由glEnd表示操作结束,由glFlush强制开始绘图。运行效果如附图1