在OpenGL ES中,需要渲染图形,无论是使用GLKit 还是使用 GLSL都不可绕开一个最最重要的步骤,那就是,顶点数据的设置.
首先来捋一下顶点数据设置的步骤:


stp1: 顶点数据
//顶点数据又有不同的情况
//情况1:顶点数组中,仅仅包含顶点数据的
GLfloat attrArr[] =
{
0.5f, -0.5f, 0.0f, //顶点D
-0.5f, 0.5f, 0.0f, //顶点A
-0.5f, -0.5f,0.0f, //顶点C
0.5f, 0.5f, 0.0f, //顶点B
-0.5f, 0.5f, 0.0f, //顶点A
0.5f, -0.5f, 0.0f, //顶点D
};
//如上图1-1所示因为一个正方形式由两个三角形构成,所以需要6个顶点.
//情况2:顶点数据中包含了纹理数据的
GLfloat attrArr[] =
{
0.5f, -0.5f, -1.0f, 1.0f, 0.0f,
-0.5f, 0.5f, -1.0f, 0.0f, 1.0f,
-0.5f, -0.5f, -1.0f, 0.0f, 0.0f,
0.5f, 0.5f, -1.0f, 1.0f, 1.0f,
-0.5f, 0.5f, -1.0f, 0.0f, 1.0f,
0.5f, -0.5f, -1.0f, 1.0f, 0.0f,
};
//情况3:使用结构体的方式来包含一个完整的顶点数据的(顶点,纹理,法线)
//我们先来定义一个包含顶点/纹理/法线的结构体
typedef struct {
GLKVector3 positionCoord; //顶点坐标
GLKVector2 textureCoord; //纹理坐标
GLKVector3 normal; //法线
} RFVertexStruct;
//然后声明一个局部变量
@implementation CubeViewController
{
RFVertexStruct _vertices[counts];//counts表示有多少个顶点数据
}
//结构体顶点数组赋值方式:
_vertices[0] = (RFVertexStruct){{-0.5, 0.5, 0.5}, {0, 1}};
//{-0.5, 0.5, 0.5} 是vertext
//{0, 1} 是顶点对应的纹理
stp2: 开辟顶点缓存区
其实所谓开辟顶点缓存区,就是在GPU中,设定一个存储区域,用于存储顶点数据的.
//开辟缓存区 VBO
GLuint vertextBuffer; //注意注意注意:顶点缓冲区是必须要释放的,当程序不再需要使用这块控件的时候
//一般在dealloc 的时候手动释放;
//这句代码起到开辟控件,并且获得空间索引的功能
glGenBuffers(1, & vertextBuffer);
//绑定缓存出去, 这句代码的实际作用就是制定这个被开辟的存储空间的使用方向;
glBindBuffer(GL_ARRAY_BUFFER, vertextBuffer);
//这个counts与上面的 数组的索引值是一直的
GLsizeiptr bufferSizeBytes = sizeof(RFVertexStruct) * counts;
//这一句代码是实际地把顶点数据从CPU-copy到GPU
glBufferData(GL_ARRAY_BUFFER, bufferSizeBytes, _vertices, GL_STATIC_DRAW);
//GL_APIENTRY glBufferData (GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage)
//参数1:是一个枚举,制定GPU的存储区域
//枚举值有四个:
#define GL_ARRAY_BUFFER //数组
#define GL_ELEMENT_ARRAY_BUFFER //索引绘图时使用到的索引数据存储区
#define GL_ARRAY_BUFFER_BINDING
#define GL_ELEMENT_ARRAY_BUFFER_BINDING
//参数2: 需要多大的存储空间 ,也就是被存储到GPU的那个数组的体积大小;
//参数3:被存储的数组在CPU的地址,其实就是数组名
//参数:GL_STATIC_DRAW:表示该缓存区不会被修改;
//GL_DyNAMIC_DRAW:表示该缓存区会被周期性更改;
//GL_STREAM_DRAW:表示该缓存区会被频繁更改;
stp3:激活顶点通道 并 设定顶点数据的读取方式
//激活顶点数据通道
glEnableVertexAttribArray(GLKVertexAttribPosition);
//设置读取方式
glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, sizeof(CCVertex), NULL + offsetof(CCVertex, positionCoord)); //使用结构体构造数组数据的时候的写法
glVertexAttribPointer(textCoor, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat)*5, (float *)NULL + 3); //使用浮点数据构造数组数据的写法
//参数1:index,顶点数据的索引
//参数2:size,每个顶点属性的坐标数量,1,2,3,或者4.默认初始值是4. (x,y,z,w);
//参数3:type,数据中的每个坐标的的数据类型,常用的有GL_FLOAT,GL_BYTE,GL_SHORT。默认初始值为GL_FLOAT
//参数4:normalized,固定点数据值是否应该归一化,或者直接转换为固定值。(GL_FALSE)
//参数5:stride,连续顶点属性之间的偏移量,默认为0;
//参数6:指定一个指针,指向数组中的第一个顶点属性的第一个元素。默认为0
stp4:激活纹理通道 并 设定纹理数据的读取方式
//纹理数据
glEnableVertexAttribArray(GLKVertexAttribTexCoord0);
glVertexAttribPointer(GLKVertexAttribTexCoord0, 2, GL_FLOAT, GL_FALSE, sizeof(CCVertex), NULL + offsetof(CCVertex, textureCoord));
注意!注意!注意!
iOS在默认情况下是关闭所有的顶点属性通道的,所以才会有
void glEnableVertexAttribArray(GLuint index);
网友评论