写入gl_FragColor会导致Android上出现INVALID_OPERATION

时间:2013-09-29 11:02:05

标签: opengl-es android-ndk opengl-es-2.0 glsl glsles

我正在尝试为NDK掌握OGLES2并坚持使用GLSL着色器。这种情况类似于the one already highlighted here,但似乎背后的原因有些不同。

我可以使用最简单的着色器。

顶点:

#version 110
attribute vec3 vPosition;
void main(void)
{
    gl_Position = vec4(vPosition, 1.0);
    gl_FrontColor = gl_BackColor = vec4(0.3, 0.3, 0.3, 1); // ***
}

片段:

#version 110
void main(void)
{
    gl_FragColor = gl_Color;
}

简单直接。我甚至在剪辑空间中直接定义了三角形。 当我运行应用时,VS源代码中的已加星标(***)行使glUseProgram调用抛出GL_INVALID_OPERATION错误(所有后续glGetAttribLocation调用都会执行相同操作)在我的Android 403设备上。我可以写入FS中的gl_FragColor(某些硬编码的vec4值),但甚至无法触及VS中的gl_FrontColor / gl_BackColor值。

E/Adreno200-ES20(16211): <qgl2DrvAPI_glUseProgram:1344>: GL_INVALID_OPERATION
E/Adreno200-ES20(16211): <qgl2DrvAPI_glGetAttribLocation:531>: GL_INVALID_OPERATION

我在着色器编译和链接期间检查每个可能的错误(glGetErrorglGetShaderInfoLog),一切都很清楚。

当我将OGL实现切换到JOGL实现时,应用程序在Windows上正常工作(所有引导和呈现代码保持不变)。我甚至可以使用包含颜色的顶点属性,完全没有问题。

有没有办法解决这个问题?我不相信Android OGLES实现 生病了,可能我只是错过了一些功能 ......

1 个答案:

答案 0 :(得分:15)

OpenGL ES 2.0没有正面/背面颜色。这已从核心OpenGL 3.x中删除,同时从未引入OpenGL ES 2.0。同样,gl_Color在您的片段着色器中无效。

从技术上讲,我认为#version 110也是无效的,因为我从未在OpenGL ES中遇到过GLSL 110的正式规范。这很可能是人们从桌面GL继承的坏习惯(从OpenGL 2.0开始在#version 110中引入了GLSL)。 GLSL 100 确实存在但不是正确批准的规范;它使用非常古老的ARB扩展。

OpenGL ES 2.0使用#version 100引入 GLSL ES ,正确的GLSL ES着色器应以#version 100(OpenGL ES 2.0)或#version 300开头( OpenGL ES 3.0)。

<小时/> 下面是使用最初为桌面OpenGL设计的着色器(兼容性配置文件)时可能遇到的一些预先声明的变量:

顶点

  • gl_FrontColor
  • gl_BackColor
  • gl_FrontSecondaryColor
  • gl_BackSecondaryColor

片段

  • gl_Color
  • gl_SecondaryColor

在核心OpenGL 3.x或OpenGL ES 2.0中,这些都不是有效的 ;为此,您必须创建自己的变化,在顶点着色器和片段着色器之间共享。


为了纠正您的情况,我更新了您的顶点和片段着色器,以避免使用gl_FrontColorgl_Color等。

修改后的顶点着色器:

#version 100

attribute vec3 vPosition;

// Vertex and Fragment Shaders will both use this varying to communicate
//   interpolated color between vertices...
varying   vec4 color;

void main (void)
{
    gl_Position = vec4 (vPosition, 1.0);
    color       = vec4 (0.3, 0.3, 0.3, 1.0);
}

Modified Fragment Shader:

#version 100

/* This takes the place of the old *gl_Color*, but it does not handle
 *   polygon side. If you _really_ do need a different color for
 *     front and back, then you will have to do things a little
 *       differently (SEE BELOW).
 */
varying vec4 color;

void main(void)
{
    gl_FragColor = color;
}


很少有人真正需要不同的颜色,但如果你真的这样做,这就是你如何实现这一目标。为了在OpenGL ES 2.0中实现每面颜色,您可以使用内置的gl_FrontFacing。此变量是一个布尔值,用于指示多边形的哪一侧被着色。

假设的双面片段着色器:

#version 100

varying vec4 front_color;
varying vec4 back_color;

void main (void) {
  gl_FragColor = gl_FrontFacing ? front_color : back_color;
}

如果您正在使用教程学习GLSL,我怀疑您正在使用基于桌面OpenGL的教程。 OpenGL的GLSL和OpenGL | ES的GLSL之间略有不同,而在ES 2.0中,GLSL语法大致相当于OpenGL的GLSL 120.

总体上最大的不同之处在于,大多数仅在桌面OpenGL中被弃用的东西实际上是从OpenGL | ES中删除的。这就是为什么遵循桌面GL教程可能不是那么好--OpenGL 3.0引入了GLSL版本130,它具有ES 2.0无法理解的语法。与此同时,为OpenGL 3.0编写的教程是最有可能避免使用已弃用功能的教程。

尽管OpenGL和OpenGL | ES源自相同的API,但是这样的细微差别使得很难为一个API编写教程并将其应用到另一个API: - \

我已经在答案的第一部分中讨论了每个版本的OpenGL,Op​​enGL ES,GLSL和GLSL ES的规范链接,以帮助您真正“掌握”OGLES2。