glGetAttribLocation returns -1 我的属性之一
glGetAttribLocation returns -1 on one of my attributes
glGetAttribLocation returns -1 我的 3 个属性之一(颜色)。检查错误、状态等,所有 returns 都是肯定的。在 Android 7 上使用 OpenGL ES2。只是找不到原因,颜色的设置方式对我来说与 texcoord 相同。
顶点着色器:
#version 100
attribute vec2 position;
attribute vec3 color;
attribute vec2 texcoord;
varying vec3 Color;
varying vec2 Texcoord;
void main()
{
Color = color;
gl_Position = vec4(position, 0.0, 1.0);
Texcoord = texcoord;
}
片段着色器:
#version 100
precision mediump float;
varying vec3 Color;
varying vec2 Texcoord;
vec4 outColor;
uniform sampler2D tex;
void main()
{
outColor = texture2D(tex, Texcoord) * vec4(Color, 1.0);
}
代码:
GLuint GlHelper::loadShader(char* fragment, char* vertex)
{
off_t fLength;
const char *vertexSource = FileManager::ReadFile(vertex,fLength);
// Create vertex shader
GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader, 1, &vertexSource, NULL);
glCompileShader(vertexShader);
GLint status; GLint logLength;
glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &status);
glGetShaderiv(vertexShader,GL_INFO_LOG_LENGTH,&logLength);
if (status != GL_TRUE)
{
char buffer[logLength];
glGetShaderInfoLog(vertexShader, logLength, NULL, buffer);
__android_log_print(ANDROID_LOG_ERROR, QS_OPENGLTAG, "%s",buffer);
return 0;
}
off_t fLength2;
const char *fragmentSource = FileManager::ReadFile(fragment,fLength2);
GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fragmentSource, NULL);
glCompileShader(fragmentShader);
glGetShaderiv(fragmentShader,GL_COMPILE_STATUS, &status);
glGetShaderiv(fragmentShader,GL_INFO_LOG_LENGTH,&logLength);
if (status != GL_TRUE)
{
char buffer[logLength];
glGetShaderInfoLog(fragmentShader, logLength, NULL, buffer);
__android_log_print(ANDROID_LOG_ERROR, QS_OPENGLTAG,"%s", buffer);
return 0;
}
GLuint shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
glLinkProgram(shaderProgram);
glGetProgramiv(shaderProgram,GL_LINK_STATUS,&status);
glGetProgramiv(shaderProgram,GL_INFO_LOG_LENGTH,&logLength);
if(status != GL_TRUE)
{
char buffer[logLength];
glGetProgramInfoLog(shaderProgram,logLength,NULL,buffer);
__android_log_print(ANDROID_LOG_ERROR,QS_OPENGLTAG,"%s",buffer);
return 0;
}
// Validate and error check.
glValidateProgram(shaderProgram);
glGetProgramiv(shaderProgram, GL_VALIDATE_STATUS, &status);
if(status != GL_TRUE)
{
char buffer[512];
glGetProgramInfoLog(shaderProgram,512,NULL,buffer);
__android_log_print(ANDROID_LOG_ERROR,QS_OPENGLTAG,"%s",buffer);
return 0;
}
glUseProgram(shaderProgram);
GLenum err = glGetError();
if(err != GL_NO_ERROR)
{
__android_log_print(ANDROID_LOG_ERROR,QS_OPENGLTAG,"%s","OpenGL error code: ");
return 0;
}
GLint posAttrib = glGetAttribLocation(shaderProgram, "position"); // works
glEnableVertexAttribArray(posAttrib);
glVertexAttribPointer(posAttrib, 2, GL_FLOAT, GL_FALSE, 7*sizeof(float), 0);
GLint colAttrib = glGetAttribLocation(shaderProgram, "color"); // returns -1
glEnableVertexAttribArray(colAttrib);
glVertexAttribPointer(colAttrib, 3, GL_FLOAT, GL_FALSE, 7*sizeof(float), (void*)(2*sizeof(float)));
GLint texAttrib = glGetAttribLocation(shaderProgram, "texcoord"); // works
glEnableVertexAttribArray(texAttrib);
glVertexAttribPointer(texAttrib, 2, GL_FLOAT, GL_FALSE, 7*sizeof(float), (void*)(5*sizeof(float)));
return shaderProgram;
这是我的读取文件函数,以防它出错:
const char* FileManager::ReadFile(const char *path, off_t& length)
{
AAsset*
asset=AAssetManager_open(FileManager::assetManager,path,AASSET_MODE_BUFFER);
char* buff = new char[AAsset_getLength(asset)];
length = AAsset_getLength(asset);
AAsset_read(asset,buff,(size_t)length);
AAsset_close(asset);
return buff;
}
见OpenGL ES Shading Language 1.00 Specification; 7.2 Fragment Shader Special Variables; page 60:
The output of the fragment shader is processed by the fixed function operations at the back end of the OpenGL ES pipeline. Fragment shaders output values to the OpenGL ES pipeline using the built-in variables gl_FragColor
and gl_FragData
, unless the discard keyword is executed.
这意味着您必须在片段着色器中写入 gl_FragColor
(而不是变量 outColor
):
gl_FragColor = texture2D(tex, Texcoord) * vec4(Color, 1.0);
在 OpenGL ES Shading Language 3.00 中,您可以对片段着色器输出变量使用 out
限定符:
out vec4 outColor;
void main()
{
outColor = texture2D(tex, Texcoord) * vec4(Color, 1.0);
}
请注意,如果您不写入 gl_FragColor
,则不会使用可变变量 Color
和 Texcoord
(由编译器优化)。这导致属性 color
和 texcoord
未被使用并且可能未激活。
见OpenGL ES 2 Specifications - 2.10.4 Shader Variables - p. 32:
A generic attribute variable is considered active if it is determined by the compiler and linker that the attribute may be accessed when the shader is executed. Attribute variables that are declared in a vertex shader but never used are not considered active. In cases where the compiler and linker cannot make a conclusive determination, an attribute will be considered active.
.....
To determine the set of active vertex attributes used by a program, and to determine their types, use the command:
void GetActiveAttrib( uint program, uint index, sizei bufSize, sizei *length, int *size, enum *type, char *name );
.....
After a program object has been linked successfully, the bindings of attribute variable names to indices can be queried. The command
int GetAttribLocation( uint program, const char *name );
glGetAttribLocation returns -1 我的 3 个属性之一(颜色)。检查错误、状态等,所有 returns 都是肯定的。在 Android 7 上使用 OpenGL ES2。只是找不到原因,颜色的设置方式对我来说与 texcoord 相同。
顶点着色器:
#version 100
attribute vec2 position;
attribute vec3 color;
attribute vec2 texcoord;
varying vec3 Color;
varying vec2 Texcoord;
void main()
{
Color = color;
gl_Position = vec4(position, 0.0, 1.0);
Texcoord = texcoord;
}
片段着色器:
#version 100
precision mediump float;
varying vec3 Color;
varying vec2 Texcoord;
vec4 outColor;
uniform sampler2D tex;
void main()
{
outColor = texture2D(tex, Texcoord) * vec4(Color, 1.0);
}
代码:
GLuint GlHelper::loadShader(char* fragment, char* vertex)
{
off_t fLength;
const char *vertexSource = FileManager::ReadFile(vertex,fLength);
// Create vertex shader
GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader, 1, &vertexSource, NULL);
glCompileShader(vertexShader);
GLint status; GLint logLength;
glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &status);
glGetShaderiv(vertexShader,GL_INFO_LOG_LENGTH,&logLength);
if (status != GL_TRUE)
{
char buffer[logLength];
glGetShaderInfoLog(vertexShader, logLength, NULL, buffer);
__android_log_print(ANDROID_LOG_ERROR, QS_OPENGLTAG, "%s",buffer);
return 0;
}
off_t fLength2;
const char *fragmentSource = FileManager::ReadFile(fragment,fLength2);
GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fragmentSource, NULL);
glCompileShader(fragmentShader);
glGetShaderiv(fragmentShader,GL_COMPILE_STATUS, &status);
glGetShaderiv(fragmentShader,GL_INFO_LOG_LENGTH,&logLength);
if (status != GL_TRUE)
{
char buffer[logLength];
glGetShaderInfoLog(fragmentShader, logLength, NULL, buffer);
__android_log_print(ANDROID_LOG_ERROR, QS_OPENGLTAG,"%s", buffer);
return 0;
}
GLuint shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
glLinkProgram(shaderProgram);
glGetProgramiv(shaderProgram,GL_LINK_STATUS,&status);
glGetProgramiv(shaderProgram,GL_INFO_LOG_LENGTH,&logLength);
if(status != GL_TRUE)
{
char buffer[logLength];
glGetProgramInfoLog(shaderProgram,logLength,NULL,buffer);
__android_log_print(ANDROID_LOG_ERROR,QS_OPENGLTAG,"%s",buffer);
return 0;
}
// Validate and error check.
glValidateProgram(shaderProgram);
glGetProgramiv(shaderProgram, GL_VALIDATE_STATUS, &status);
if(status != GL_TRUE)
{
char buffer[512];
glGetProgramInfoLog(shaderProgram,512,NULL,buffer);
__android_log_print(ANDROID_LOG_ERROR,QS_OPENGLTAG,"%s",buffer);
return 0;
}
glUseProgram(shaderProgram);
GLenum err = glGetError();
if(err != GL_NO_ERROR)
{
__android_log_print(ANDROID_LOG_ERROR,QS_OPENGLTAG,"%s","OpenGL error code: ");
return 0;
}
GLint posAttrib = glGetAttribLocation(shaderProgram, "position"); // works
glEnableVertexAttribArray(posAttrib);
glVertexAttribPointer(posAttrib, 2, GL_FLOAT, GL_FALSE, 7*sizeof(float), 0);
GLint colAttrib = glGetAttribLocation(shaderProgram, "color"); // returns -1
glEnableVertexAttribArray(colAttrib);
glVertexAttribPointer(colAttrib, 3, GL_FLOAT, GL_FALSE, 7*sizeof(float), (void*)(2*sizeof(float)));
GLint texAttrib = glGetAttribLocation(shaderProgram, "texcoord"); // works
glEnableVertexAttribArray(texAttrib);
glVertexAttribPointer(texAttrib, 2, GL_FLOAT, GL_FALSE, 7*sizeof(float), (void*)(5*sizeof(float)));
return shaderProgram;
这是我的读取文件函数,以防它出错:
const char* FileManager::ReadFile(const char *path, off_t& length)
{
AAsset*
asset=AAssetManager_open(FileManager::assetManager,path,AASSET_MODE_BUFFER);
char* buff = new char[AAsset_getLength(asset)];
length = AAsset_getLength(asset);
AAsset_read(asset,buff,(size_t)length);
AAsset_close(asset);
return buff;
}
见OpenGL ES Shading Language 1.00 Specification; 7.2 Fragment Shader Special Variables; page 60:
The output of the fragment shader is processed by the fixed function operations at the back end of the OpenGL ES pipeline. Fragment shaders output values to the OpenGL ES pipeline using the built-in variables
gl_FragColor
andgl_FragData
, unless the discard keyword is executed.
这意味着您必须在片段着色器中写入 gl_FragColor
(而不是变量 outColor
):
gl_FragColor = texture2D(tex, Texcoord) * vec4(Color, 1.0);
在 OpenGL ES Shading Language 3.00 中,您可以对片段着色器输出变量使用 out
限定符:
out vec4 outColor;
void main()
{
outColor = texture2D(tex, Texcoord) * vec4(Color, 1.0);
}
请注意,如果您不写入 gl_FragColor
,则不会使用可变变量 Color
和 Texcoord
(由编译器优化)。这导致属性 color
和 texcoord
未被使用并且可能未激活。
见OpenGL ES 2 Specifications - 2.10.4 Shader Variables - p. 32:
A generic attribute variable is considered active if it is determined by the compiler and linker that the attribute may be accessed when the shader is executed. Attribute variables that are declared in a vertex shader but never used are not considered active. In cases where the compiler and linker cannot make a conclusive determination, an attribute will be considered active.
.....
To determine the set of active vertex attributes used by a program, and to determine their types, use the command:
void GetActiveAttrib( uint program, uint index, sizei bufSize, sizei *length, int *size, enum *type, char *name );
.....
After a program object has been linked successfully, the bindings of attribute variable names to indices can be queried. The command
int GetAttribLocation( uint program, const char *name );