顶点属性声明

一个属性可以声明在一个顶点着色器,但如果它不使用,那么它是不被激活的。你能使用glGetActiveAttrib查询一个被激活的属性内容。GL_ACTIVE_ATTRIBUTES

void glGetActiveAttrib( GLuint program, GLuint index, GLsizei bufsize,
                        GLsizei *length, GLint *size, GLenum *type, GLchar *name)

bufsize是那些能被写为属性名的字符的最大数目,包括空('\0')。length是返回的名字长度,type是数据的类型GL_FLOAT等。size是返回的属性大小,是返回type的单位大小,如果是数组就是数组的尺寸,不是数组就是1。name是着色器声明的属性变量的名字。

顶点着色器中使用glBindAttribLocation绑定一个普通的顶点属性索引到属性变量,这个绑定在项目下次链接时有效,在当前链接的项目里不会改变。如果一个名字前面被绑定过,它分配的绑定被一个索引取代。glBindAttribLocation甚至能在顶点着色器被连接到一个项目对象前使用。这意味着这个调用能被使用去绑定任何属性名字。属性名字不存在或者没激活的绑定在项目里被忽略。

void glBindAttribLocation(GLuint program, GLuint index, const GLchar *name)

另一种选择是让GLES绑定属性变量名到一个普通的属性索引。在链接阶段GLES2为每个属性变量执行下面的步骤:检查每个属性变量是否已通过glBindAttribLocation绑定。如果已绑定,指定的属性索引将被使用;如果没有,编译工具将产生一个一般的顶点属性索引。而这个分配依赖工具的不同而不同,我们可以使用glGetAttribLocation去获取这个分配的值。

GLint glGetAttribLocation(GLuint program, const GLchar *name)

指定顶点属性数据:

  • 指定顶点属性常量

void glVertexAttrib1f(GLuint index, GLfloat x);
void glVertexAttrib2f(GLuint index, GLfloat x, GLfloat y);
void glVertexAttrib3f(GLuint index, GLfloat x, GLfloat y, GLfloat z);
void glVertexAttrib4f(GLuint index, GLfloat x, GLfloat y, GLfloat z,
GLfloat w);
void glVertexAttrib1fv(GLuint index, const GLfloat *values);
void glVertexAttrib2fv(GLuint index, const GLfloat *values);
void glVertexAttrib3fv(GLuint index, const GLfloat *values);
void glVertexAttrib4fv(GLuint index, const GLfloat *values);

index是要装载的顶点属性索引,x y z values是要填充的值。glVertexAttrib?f和glVertexAttrib?fv都是装载一个vec4的值。介绍Shader语言时说过它们都会存储为具有4个分量的存储单元。填充时最后一个会为1.0,中间不足的为0.0。如glVertexAttrib1fv填充1,那么index最终的值为{x,0.0,0.0,1.0}。注意到GLES2只支持了浮点型的设置属性常量api。

  • 顶点数组

void glVertexAttribPointer( GLuint index, GLint size, GLenum type,
                            GLboolean normalized,
                            GLsizei stride,
                            const void *ptr)

要装在数组到顶点属性,使用glVertexAttribPointer,index是顶点属性的索引,size是数组里组成元素的大小(例如只是指定二维的位置那么只需要x,y那么赋值为2),type是数据格式,normalized用于指定非浮点数据格式转变成浮点型数据时是否标准化,strides是顶点属性数据的存储间隔,0表示无间隔,连续存储的。ptr就是我们要放进去的数据了。正如第二节例子里的:

// _vPositionHandle的值就来自于glGetAttribLocation获取得到的索引
glVertexAttribPointer(_vPositionHandle, 2, GL_FLOAT, GL_FALSE, 0, gTriangleVertices);

出了加载数据,我们还要为属性启用属性数组。

// 启用
void glEnableVertexAttribArray(GLuint index);
// 不启用
void glDisableVertexAttribArray(GLuint index);
// index就是前面的属性索引值

栗子

接着以前的项目,这里我们主要修改Director里的内容:代码看里面的lesson5的tag

想声明着色器和全局数据

// 顶点着色器,声明俩个着色器属性,分别放位置和颜色,易变变量作为输出将传给片段着色器
static const char gVertexShader[] =
    "attribute vec4 a_position;\n"
    "attribute vec4 a_color;\n"
    "varying vec4 v_color;\n"
    "void main()\n"
    "{\n"
    "  v_color = a_color;\n"
    "  gl_Position = a_position;\n" 
    "}\n";
// 片段着色器,接收颜v_color传来的颜色
static const char gFragmentShader[] =
    "varying vec4 v_color;\n"
    "void main()\n"
    "{\n"
    "  gl_FragColor = v_color;\n"
    "}\n";
// 和以前的一样的三角形数据
const GLfloat gTriangleVertices[] = { 0.0f, 0.5f, -0.5f,
                                     -0.5f, 0.5f, -0.5f };
// 接下来用给a_color的
const GLfloat gColor[4] = { 1.0f, 1.0f, 0.0f, 1.0f };

在mainloop循环中修改

void Director::mainLoop()
{
    static float grey;
    grey += 0.01f;
    if (grey > 1.0f) {
        grey = 0.0f;
    }
    glClearColor(grey, grey, grey, 1.0f);
    glClear( GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);

    glVertexAttrib4fv(0, gColor);
    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, gTriangleVertices); 
    glEnableVertexAttribArray(1);
    glBindAttribLocation(_glProgram->getProgramHandle(), 0, "a_color"); 
    glBindAttribLocation(_glProgram->getProgramHandle(), 1, "a_position");
    glDrawArrays(GL_TRIANGLES, 0, 3);
}

查看效果,可以看到我们设置的黄色三角形:

clipboard.png


RichardXG
337 声望19 粉丝

引用和评论

0 条评论