传统绘图与索引绘图的区别
我们使用传统的数组绘制方式绘制一个立方体时,可能每个面使用6个顶点(绘制两个三角形),其中2个顶点是共享的,重复的上个月专业户,那么一共需要制定36个顶点;如果使用索引绘图的话,不需要为重复的顶点再分配内存,实际上只需要24个顶点数据。
索引绘图
为了在多个三角形之间共享属性数据,我们需要通过索引数组对属性数组进行访问。
索引绘制需要做两件事:一个构造良好的索引数组和一个新的索引绘制命令。
索引数组
索引数组,存储在缓存对象中,它有一个特别的缓存对象,GL_ELEMENT_ARRAY_BUFFER
. 你可以使用这个缓存对象来作为正常的缓存对象使用,就像GL_ARRAY_BUFFER
。但是对于OpenGL他有特殊含义,那就是索引绘图必须使用这个缓存对象。
索引绘制命令
为了进行索引绘图,我们需要将索引数组绑定到GL_ELEMENT_ARRAY_BUFFER
,然后调用glDrawElements
。
//使用索引绘图
/*
void glDrawElements(GLenum mode,GLsizei count,GLenum type,const GLvoid * indices);
参数列表:
mode:要呈现的画图的模型
GL_POINTS
GL_LINES
GL_LINE_LOOP
GL_LINE_STRIP
GL_TRIANGLES
GL_TRIANGLE_STRIP
GL_TRIANGLE_FAN
count:绘图个数
type:类型
GL_BYTE
GL_UNSIGNED_BYTE
GL_SHORT
GL_UNSIGNED_SHORT
GL_INT
GL_UNSIGNED_INT
indices:绘制索引数组
*/
glDrawElements(GL_TRIANGLES, sizeof(indices) / sizeof(indices[0]), GL_UNSIGNED_INT, indices);
金字塔绘图图解
-
顶点数据
顶点数据.jpg -
金字塔底部
金字塔底部索引数据.jpg -
金字塔四侧
金字塔四侧索引信息.jpg
使用给定索引数组方式实现索引绘图方式
顶点着色器代码
attribute vec4 position;
attribute vec4 positionColor;
uniform mat4 projectionMatrix;
uniform mat4 modelViewMatrix;
varying lowp vec4 varyColor;
void main()
{
varyColor = positionColor;
vec4 vPos;
//4*4 * 4*4 * 4*1
vPos = projectionMatrix * modelViewMatrix * position;
//ERROR
//vPos = position * modelViewMatrix * projectionMatrix ;
gl_Position = vPos;
}
片元着色器代码
varying lowp vec4 varyColor;
void main()
{
gl_FragColor = varyColor;
}
渲染流程
GLSL自定义着色器索引绘制流程.jpg渲染部分核心代码
GLfloat attrArr[] =
{
-0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 1.0f, //左上0
0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 1.0f, //右上1
-0.5f, -0.5f, 0.0f, 1.0f, 1.0f, 1.0f, //左下2
0.5f, -0.5f, 0.0f, 1.0f, 1.0f, 1.0f, //右下3
0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, //顶点4
};
//(2).索引数组
GLuint indices[] =
{
0, 3, 2,
0, 1, 3,
0, 2, 4,
0, 4, 1,
2, 3, 4,
1, 4, 3,
};
//(3).判断顶点缓存区是否为空,如果为空则申请一个缓存区标识符
if (self.myVertices == 0) {
glGenBuffers(1, &_myVertices);
}
//9.-----处理顶点数据-------
//(1).将_myVertices绑定到GL_ARRAY_BUFFER标识符上
glBindBuffer(GL_ARRAY_BUFFER, _myVertices);
//(2).把顶点数据从CPU内存复制到GPU上
glBufferData(GL_ARRAY_BUFFER, sizeof(attrArr), attrArr, GL_DYNAMIC_DRAW);
GLuint position = glGetAttribLocation(self.myProgram, "position");
glEnableVertexAttribArray(position);
glVertexAttribPointer(position, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 6, NULL);
GLuint positionColor = glGetAttribLocation(self.myProgram, "positionColor");
glEnableVertexAttribArray(positionColor);
glVertexAttribPointer(positionColor, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 6, (GLfloat *) NULL + 3 );
GLuint projectionMatrix = glGetUniformLocation(self.myProgram, "projectionMatrix");
GLuint modelViewMatrix = glGetUniformLocation(self.myProgram, "modelViewMatrix");
float width = self.frame.size.width;
float height = self.frame.size.height;
float aspect = width/ height;
GLKMatrix4 _projectionMatrix = GLKMatrix4MakePerspective(GLKMathDegreesToRadians(30.f), aspect, 5.0f, 20.0);
_projectionMatrix = GLKMatrix4Scale(_projectionMatrix, 1.0f, 1.0f, 1.0f);
glUniformMatrix4fv(projectionMatrix, 1, false, (GLfloat *)&_projectionMatrix.m00);
GLKMatrix4 _modelViewMatrix = GLKMatrix4Translate(GLKMatrix4Identity, 0, 0, -10.0f);
GLKMatrix4 _rotationMatrix = GLKMatrix4Rotate(GLKMatrix4Identity, GLKMathDegreesToRadians(xDegree), 1.0, 0.0, 0.0);
_rotationMatrix = GLKMatrix4Rotate(_rotationMatrix, GLKMathDegreesToRadians(yDegree), 0.0, 1.0, 0.0);
_rotationMatrix = GLKMatrix4Rotate(_rotationMatrix, GLKMathDegreesToRadians(zDegree), 0.0, 0.0, 1.0);
GLKMatrix4 _lastMatrix = GLKMatrix4Multiply(_modelViewMatrix, _rotationMatrix);
glUniformMatrix4fv(modelViewMatrix, 1, false, (GLfloat *)&_lastMatrix.m00);
glEnable(GL_CULL_FACE);
//
glDrawElements(GL_TRIANGLES, sizeof(indices) / sizeof(indices[0]), GL_UNSIGNED_INT, indices);
[self.myContext presentRenderbuffer:GL_RENDERBUFFER];
使用索引缓冲区方式实现索引绘图
-
将索引数组存储到索引缓冲区
//将索引数组存储到索引缓冲区 GL_ELEMENT_ARRAY_BUFFER
GLuint index;
glGenBuffers(1, &index);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
-
绘制时,绘制索引数组置为0
glDrawElements(GL_TRIANGLES, self.count, GL_UNSIGNED_INT, 0);
网友评论