opengl学习(三)----绘制简单图形(一)
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
opengl学习(三)----绘制简单图形(⼀)
今天说⼀说⼏种简单的图元。
所有的⼏何图元都是根据它们的顶点来描绘的。
⽽顶点就是它们在屏幕上的坐标位置。
我喜欢把这⼏个简单的图元称为点线⾯。
点,可以看到⼀个顶点;
线,就是两个顶点指定的⼀条有限长度的线段;
⾯,其实更准确讲是⼀个凸多边形。
opengl⾥所讲的多边形是内部⽤颜⾊填充的,视觉上称为⾯我个⼈认为是更贴近的。
当然,多边形也是由指定的顶点组成的。
需要注意的是,要想被opengl按照设计被绘制必须正确的认识到,所谓的多边形是顶点都处于⼀个平⾯上,凸多边形。
凸多边形不能理解的,请问度娘。
来看⼀个例⼦:
C++代码
1. glBegin(GL_POLYGON);
2. glVertex2f(0.0, 0.0);
3. glVertex2f(0.0, 3.0);
4. glVertex2f(4.0, 3.0);
5. glVertex2f(
6.0, 1.5);
6. glVertex2f(4.0, 0.0);
7. glEnd();
先不去关⼼代码本⾝,这段代码最终的结果是要指定5个顶点绘制⼀个凸五边形。
注意,不是5条线段⽽是⼀个凸五边形的平⾯。
不管是点线⾯的哪⼀种,都是需要指定⼀组顶点的。
如何判定顶点指定的开始和结束就是glBegin和glEnd的⼯作。
引⽤
void glBegin(Glenum mode);
标志着⼀个顶点数据列表的开始,它描述了⼀个⼏何图元。
mode参数指定了图元的类型。
void glEnd(void);
标志着⼀个顶点数据列表的结束。
mode设置的不同,代表着将要绘制的图元也不同。
下⾯这个表就是图元的名称和含义:
值含义
GL_POINTS 单个的点
GL_LINES ⼀对顶点被解释为⼀条直线
GL_LINE_STRIP ⼀系列的连接直线
GL_LINE_LOOP 和上⾯相同,但第⼀个顶点和最后⼀个顶点彼此相连
GL_TRIANGLES 3个顶点被解释为⼀个三⾓形
GL_TRIANGLES_STRIP 三⾓形的连接串
GL_TRIANGLES_FAN 连接成扇形的三⾓形系列
GL_QUADS 4个顶点被解释为⼀个四边形
GL_QUADS_STRIP 四边形的连接串
GL_POLYGON 简单的凸多边形的边界
试想着,如果将glBegin(GL_POLYGON)修改为glBegin(GL_POINTS),绘制出来的将是什么图形呢? 哈哈,那就是5个点⽽已么。
上⾯那段代码还有⼀个最为重要的函数,那就是顶点函数只有通过顶点函数指定了绘制图形所需要的顶点,才能去绘制我们需要的图形。
下⾯看⼀下顶点函数的原形:
引⽤
void glVertex[234]{sifd}(TYPE coords);
glVertex[234]{sifd}(const TYPE *coords);
指定了⼀个⽤于描述⼏何物体的顶点。
可以选择这个函数的适当版本,即可以为⼀个顶点提供多达4个的坐标(x,y,z,w),也可以只提供2个坐标(x,y)。
如果选择的函数版本并没有显式地指定z或者w,z就会当作0,w则默认为1。
glVertext*()函数只有当它位于glBegin()和glEnd()之间时才有效。
上⼀周简简单单的讲了⼀下简单图形的绘制。
按照所讲内容绘制⼀个20条边的多边形,那需要调⽤多少函数呢?⾄少22个。
⾸先调⽤glBegin(),然后是20个顶点函数,最后调⽤⼀个glEnd()函数。
再如果,要绘制⼀个⽴⽅体。
⼀个⽴⽅体有6个⾯,⼀个⾯有四个顶点,也就是⾄少要定义26个函数。
可是⼀个⽴⽅体按照数学⾥⾯的算法是只有8个顶点,如果按照我们绘制多边形的这种⽅式,每个顶点都指定了3次,才可以将所有的平⾯绘制完成形成⼀个⽴⽅体。
好吧,我承认,我是要说,这显然,太~浪~费~了。
OpenGL是不会这么⽆耻的允许这样浪费的事情存在的,所以⼤家不⽤纠结,继续往下看吧。
OpenGL提供了顶点数组函数,允许只⽤少数⼏个数组指定⼤量的与顶点相关的数据,并⽤少量函数调⽤访问这些数据。
使⽤顶点数组对⼏何图形进⾏渲染需要三个步骤:
第⼀,启⽤数组。
引⽤
void glEnableClientState(GLenum array)
指定了需要启⽤的数组。
array参数可以使⽤下⾯这些符号常量:GL_VERTEY_ARRAY、GL_COLOR_ARRAY、
GL_SECONDARY_COLOR_ARRAY、GL_INDEX_ARRAY、GL_NORMAL_ARRAY、GL_FOG_COORDINATE_ARRAY、
GL_TEXTURE_COORD_ARRAY和GL_EDGE_FLAG_ARRAY
第⼀个步骤是使⽤上⾯这个函数,激活选择的数组。
例如激活顶点坐标数组就是glEnableClientState(GL_VERTEY_ARRAY)。
有启⽤就⽤禁⽤,下⾯这个函数即为禁⽤函数。
引⽤
void glDisableClientState(GLenum array)
指定了需要禁⽤的数组。
它接受的参数与glEnableClientState()函数相同。
第⼆,指定数组的数据。
共⽤8个不同的函数指定数组,每个函数⽤于指定⼀个不同类型的数组。
引⽤
void glVertexPointer(GLint size, GLenum type, GLsizei stride,const GLvoid *pointer);
指定了需要访问的空间坐标数据。
pointer:顶点坐标的内存地址;
type:数组数据的类型(GL_SHORT、GL_INT、GL_FLOAT或GL+DOUBLE)。
size:顶点的坐标数量,必须为2、3、4.
stride:连续顶点之间的字节偏移量。
如果为0,则表⽰顶点是相邻的。
其它7个函数如下:
glColorPointer(GLint size, GLenum type, GLsizei stride,const GLvoid *pointer);
glSecondaryColorPointer(GLint size, GLenum type, GLsizei stride,const GLvoid *pointer);
glIndexPointer(GLint size, GLenum type, GLsizei stride,const GLvoid *pointer);
glNormalPointer(GLint size, GLenum type, GLsizei stride,const GLvoid *pointer);
glFogCoordPointer(GLint size, GLenum type, GLsizei stride,const GLvoid *pointer);
glTexCoordPointer(GLint size, GLenum type, GLsizei stride,const GLvoid *pointer);
glEdgeFlagPointer(GLint size, GLenum type, GLsizei stride,const GLvoid *pointer);
附上⼀个⼩的例⼦:
C++代码
1. static GLint vertices[] = {25, 25,
2. 100, 325,
3. 175, 25,
4. 175, 325,
5. 250, 25,
6. 325, 325};
7. static GLfloat colors[] = {1.0, 0.2, 0.2,
8. 0.2, 0.2, 1.0,
9. 0.8, 1.0, 2.0,
10. 0.75, 0.75, 0.75,
11. 0.35, 0.35, 0.35,
12. 0.5, 0.5, 0.5};
13. glEnableClientState(GL_COLOR_ARRAY);
14. glEnableClientState(GL_VERTEX_ARRAY);
15. glColorPointer(3, GL_FLOAT, 0, color);
16. glVertexPointer(2, GL_INT, 0, vertices);
第三,解引⽤和渲染。
解引⽤单个数组元素:
引⽤
void glArrayElement(GLint ith)
获取当前所有已启⽤数组的⼀个顶点(第ith个)的数据。
对于顶点坐标数组,对应的函数是glVertex[size][type]v(),其中size是
【2,3,4】之⼀。
type是[s,i,f,d]之⼀,size和type都是glVertexPointer()函数定义的。
对于其他启动的数组,glArrayElement()分别调⽤那个glEndgFlagv()、glTexCoord[size[[type]v()、glColor[size][type]v()、glSecondaryColor3[type]v()、glInde[type]v()、glNoramal3[type]v()和glFogCoord[type]v()。
如果启⽤了顶点坐标数组,在其他⼏个数组(如果启⽤)相对应的函数被执⾏之后,glVertex*v()函数在最后执⾏。
举例说明:使⽤第⼆步骤时启⽤的顶点数组的第1,2,3顶点绘制⼀个三⾓形:
C++代码
1. glBegin(GL_TRIANGLES);
2. glArrayElement(0);
3. glArrayElement(1);
4. glArrayElement(2);
5. glEnd();
上⾯这段代码与下⾯的效果相同:
C++代码
1. glBegin(GL_TRIANGLES);
2. glColor3fv(color);
3. glVertex2iv(vertices);
4. glColor3fv(color + (1*3));
5. glVertex2iv(vertices + (1*2));
6. glColor3fv(color + (2*3));
7. glVertex2iv(vertices + (2*2));
8. glEnd();
glArrayElement每个顶点还是调⽤⼀次,恩,不够简洁么。
再来看⼀个更简洁点⼉的。
引⽤
void glDrawElements(GLenum mode, GLsize count, GLenum type, const GLvoid *indices);
使⽤count个元素定义⼀个⼏何图元序列,这些元素的索引值保存在indices数组中。
type是indices数组中数据的类型。
mode参数指定了被创建的是哪种类型的图元。
还是以刚刚的例⼦继续替换吧,它的效果与刚刚的效果是⼀样的,还需要重复?需要,好吧。
⾃⼰copy去~~:
C++代码
1. static GLubyte indices = {0, 1, 2};
2. glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_BYTE, indices);。