glVertexAttribPointer和glEnableVertexAttribArray的范围是什么?

Dav*_*one 5 opengl opengl-es opengl-es-2.0

我在Android上使用OpenGL ES 2.0,但我认为这个问题是一般的OpenGL问题.

我正在学习OpenGL,并试图准确理解每帧必须调用哪些API,而不是只调用一次.我最初打电话glVertexAttribPointerglEnableVertexAttribArray每一帧,但当我改变我的测试程序只为每个Shader程序调用一次时,我得到的行为不是我所期望的.

似乎glVertexAttribPointer并且glEnableVertexAttribArray应该只需要调用一次,而不是每个帧,因为它们只在特定的Shader程序的上下文中才有意义.我这样说glVertexAttribPointer是因为它的第一个参数GLuint index是从glGetAttribLocation它返回的,它指定了一个与着色器程序中的变量名对应的字符串.因此,似乎数据与特定着色器程序中的特定"属性"变量相关联.

我的测试程序呈现两个不相交的形状(三角形),使用两个完全不同的程序 - 不同的片段着色器源,不同的顶点着色器源,单独的调用glLinkProgram等.我最初为每个帧运行以下代码,一切都按预期工作 - 我看到两个形状都正确呈现.

m_glhook.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);

// Shape/Program 1          
m_glhook.glUseProgram(m_iGlProgramId);
int iPositionLocation = m_glhook.glGetAttribLocation(m_iGlProgramId, "a_Position");
m_bfVertices.rewind();
m_glhook.glVertexAttribPointer(iPositionLocation, 4, GLES20.GL_FLOAT, false, STRIDE, m_bfVertices);
m_glhook.glEnableVertexAttribArray(iPositionLocation);    
gl.glDrawArrays(GLES20.GL_TRIANGLES, 0, 3);

// Shape/Program 2
m_glhook.glUseProgram(m_iGlProgramId2);
int iPositionLocation2 = m_glhook.glGetAttribLocation(m_iGlProgramId2, "a_Position");
m_bfVertices2.rewind();
m_glhook.glVertexAttribPointer(iPositionLocation2, 4, GLES20.GL_FLOAT, false, STRIDE, m_bfVertices2);
m_glhook.glEnableVertexAttribArray(iPositionLocation2);
gl.glDrawArrays(GLES20.GL_TRIANGLES, 0, 3);
Run Code Online (Sandbox Code Playgroud)

然后我修改了为每个帧进行的调用,如下所示. m_bFirstDraw第一帧为true,连续帧为false.

m_glhook.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);

// Shape/Program 1          
m_glhook.glUseProgram(m_iGlProgramId);
if (m_bFirstDraw)
{
    int iPositionLocation = m_glhook.glGetAttribLocation(m_iGlProgramId, "a_Position");
    m_bfVertices.rewind();
    m_glhook.glVertexAttribPointer(iPositionLocation, 4, GLES20.GL_FLOAT, false, STRIDE, m_bfVertices);
    m_glhook.glEnableVertexAttribArray(iPositionLocation);
}
gl.glDrawArrays(GLES20.GL_TRIANGLES, 0, 3);

// Shape/Program 2
m_glhook.glUseProgram(m_iGlProgramId2);
if (m_bFirstDraw)
{           
    int iPositionLocation2 = m_glhook.glGetAttribLocation(m_iGlProgramId2, "a_Position");
    m_bfVertices2.rewind();
    m_glhook.glVertexAttribPointer(iPositionLocation2, 4, GLES20.GL_FLOAT, false, STRIDE, m_bfVertices2);
    m_glhook.glEnableVertexAttribArray(iPositionLocation2);
}
gl.glDrawArrays(GLES20.GL_TRIANGLES, 0, 3);
m_bFirstDraw = false;
Run Code Online (Sandbox Code Playgroud)

我在上面的代码中看到的行为是,对于第一帧,一切都很好(这是有道理的,因为对于第一帧,调用序列完全相同).但是对于连续的帧,Shape1会被Shape2的顶点绘制.所以我只看到Shape2,因为它完全被绘制在Shape1之上.

请帮助我理解这一点......为什么设置一个程序的数据(形状顶点)会影响连续帧中另一个程序使用的数据?我错过了一些东西......

And*_*man 6

虽然GLSL程序(特别是顶点着色器)使用基于通用槽号的顶点属性,但实际上并没有为GLSL程序提供顶点指针.

这些指针是Vertex Array状态的一部分,在较新版本的OpenGL中完全由它处理Vertex Array Objects.如果你希望每个程序都有自己的指针集,我建议你创建一个存储状态的VAO,并在绑定程序时绑定VAO.

如果VAO不可用,则无论何时切换GLSL程序,都必须手动设置指针.注意,在这种情况下,存在全局上下文,其中存储顶点阵列指针,绑定顶点缓冲区,启用/禁用阵列等.因此,您必须小心禁用未使用的顶点属性数组,或者最终可以从无效内存中读取GL.

VAO是一个更优雅的解决方案,你应该在它们可用时支持它们.

  • @DavidStone,您可以检查 glGetString(GL_EXTENSIONS) 中的“vertex_array_object”,以了解您的 OpenGL 2.0 上下文是否恰好支持 VAO。例如,在较新的 iPhone/iPad 上,使用 kEAGLRenderingAPIOpenGLES2 创建的上下文支持它。 (2认同)