这篇文章我们同样借助上篇文章《OpenGLES-02 绘制基本图元(点、线、三角形)》的代码,使用另外一种画法来绘制一个矩形。
修改render方法如下:
代码语言:javascript复制-(void)render
{
//设置清屏颜色,默认是黑色,如果你的运行结果是黑色,问题就可能在这儿
glClearColor(0.3, 0.5, 0.8, 1.0);
/*
glClear指定清除的buffer
共可设置三个选项GL_COLOR_BUFFER_BIT,GL_DEPTH_BUFFER_BIT和GL_STENCIL_BUFFER_BIT
也可组合如:glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
这里我们只用了color buffer,所以只需清除GL_COLOR_BUFFER_BIT
*/
glClear(GL_COLOR_BUFFER_BIT);
// Setup viewport
glViewport(0, 0, self.frame.size.width, self.frame.size.height);
GLfloat vertices[] = {
// 第一个三角形
0.5f, 0.5f, 0.0f, // 右上角
0.5f, -0.5f, 0.0f, // 右下角
-0.5f, 0.5f, 0.0f, // 左上角
// 第二个三角形
0.5f, -0.5f, 0.0f, // 右下角
-0.5f, -0.5f, 0.0f, // 左下角
-0.5f, 0.5f, 0.0f // 左上角
};
glVertexAttribPointer(_positionSlot, 3, GL_FLOAT, GL_FALSE, 0, vertices);
glEnableVertexAttribArray(_positionSlot);
glDrawArrays(GL_TRIANGLES, 0, 6);
[_context presentRenderbuffer:_renderBuffer];
}
运行结果.png
如上代码所示,我们绘制的矩形是由2个三角形组成的,一个三角形3个顶点,共使用了6个顶点,其中第2个顶点与第4个顶点相同(0.5,-0.5,0.0),第3个顶点与第6个顶点相同(-0.5,0.5,0.0)。 其实对于矩形来说,它只有4个而不是6个顶点,绘制这个矩形,我们指定了右下角和左上角两次,这样就产生了50%的额外开销。还好我们这会儿只要画一个矩形,当我们要画成千上万个矩形或者别的多边形的时候,这样的绘制方法产生的额外消耗会更多从而产生一大堆浪费。 更好的解决方案是只储存不同的顶点,并设定绘制这些顶点的顺序。这样子我们只要储存4个顶点就能绘制矩形了,之后只要指定绘制的顺序就行了。还好OpenGL有这样的方式:
代码语言:javascript复制glDrawElements();
glDrawElements 函数的原型为:glDrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices);
第一个参数 mode 为描绘图元的模式,其有效值为:GL_POINTS, GL_LINES, GL_LINE_STRIP, GL_LINE_LOOP, GL_TRIANGLES, GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN。这些模式具体含义下面有介绍。
第二个参数 count 为顶点索引的个数也就是,type 是指顶点索引的数据类型,因为索引始终是正值,索引这里必须是无符号型的非浮点类型,因此只能是 GL_UNSIGNED_BYTE, GL_UNSIGNED_SHORT, GL_UNSIGNED_INT 之一,为了减少内存的消耗,尽量使用最小规格的类型如 GL_UNSIGNED_BYTE。
第三个参数 indices 是存放顶点索引的数组。(indices 是 index 的复数形式,3D 里面很多单词的复数都挺特别的。)
索引缓冲对象(简称EBO)的工作方式正是这样的。和顶点缓冲对象一样,EBO也是一个缓冲,它专门储存索引,OpenGL调用这些顶点的索引来决定该绘制哪个顶点。所谓的索引绘制(Indexed Drawing)正是我们问题的解决方案。首先,我们先要定义(独一无二的)顶点,和绘制出矩形所需的索引:
代码语言:javascript复制GLfloat vertices[] = {
0.5f, 0.5f, 0.0f, // 右上角
0.5f, -0.5f, 0.0f, // 右下角
-0.5f, -0.5f, 0.0f, // 左下角
-0.5f, 0.5f, 0.0f // 左上角
};
GLubyte indices[] = { // 注意索引从0开始!
0, 1, 3, // 第一个三角形
1, 2, 3 // 第二个三角形
};
然后整个render函数的代码该是这样的:
代码语言:javascript复制-(void)render
{
//设置清屏颜色,默认是黑色,如果你的运行结果是黑色,问题就可能在这儿
glClearColor(0.3, 0.5, 0.8, 1.0);
/*
glClear指定清除的buffer
共可设置三个选项GL_COLOR_BUFFER_BIT,GL_DEPTH_BUFFER_BIT和GL_STENCIL_BUFFER_BIT
也可组合如:glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
这里我们只用了color buffer,所以只需清除GL_COLOR_BUFFER_BIT
*/
glClear(GL_COLOR_BUFFER_BIT);
// Setup viewport
glViewport(0, 0, self.frame.size.width, self.frame.size.height);
GLfloat vertices[] = {
0.5f, 0.5f, 0.0f, // 右上角
0.5f, -0.5f, 0.0f, // 右下角
-0.5f, -0.5f, 0.0f, // 左下角
-0.5f, 0.5f, 0.0f // 左上角
};
GLubyte indices[] = { // 注意索引从0开始!
0, 1, 3, // 第一个三角形
1, 2, 3 // 第二个三角形
};
glVertexAttribPointer(_positionSlot, 3, GL_FLOAT, GL_FALSE, 0, vertices);
glEnableVertexAttribArray(_positionSlot);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, indices); //6表示有6个索引数据,可以使用sizeof(indices)/sizeof(GLubyte)来确定
[_context presentRenderbuffer:_renderBuffer];
}
两种方式的运行结果是一样的,我们可以发现,运行图中的矩形是个长方形,而我们给的坐标,照理来讲应该是正方形的,这是因为屏幕的宽高比不同,对应的openGL坐标x、y坐标也不一样,后面我们会讲到投影矩阵,投影矩阵能修复这个问题。
所有教程代码在此 : https://github.com/qingmomo/iOS-OpenGLES-