user1552075
user1552075

Reputation:

glGetAttribLocation returns -1 on one of my attributes

glGetAttribLocation returns -1 on one of my 3 attributes (color). Checking for errors, state, etc and everything returns positive. Using OpenGL ES2 on Android 7. Just cannot find the cause and the way how color is set up is identical to texcoord for me.

Vertex Shader:

#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;
   }

Fragment Shader:

#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);
} 

Code:

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;

Here is my readfile function, in case it does something wrong:

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;
}

Upvotes: 2

Views: 1246

Answers (1)

Rabbid76
Rabbid76

Reputation: 211229

See 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.

This means you have to write to gl_FragColor in the fragment shader (instead of the varaible outColor):

gl_FragColor = texture2D(tex, Texcoord) * vec4(Color, 1.0);

In OpenGL ES Shading Language 3.00 you would be able to use the out qualifier for a fragment shader output variable:

out vec4 outColor;

void main()
{
    outColor = texture2D(tex, Texcoord) * vec4(Color, 1.0);
} 


Note if you do not write to gl_FragColor, then the varying variables Color and Texcoord are not used (optimized by the compiler). This causes that the attributes color and texcoord are not used and may not be active.

See 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 );

Upvotes: 1

Related Questions