2
\$\begingroup\$

I'm developping an OpenGLes 3.0 app with Java and I started writing the shader code. For some reason, it seems to mix up the attributes data locations and I don't understand why. Here's the code :

Vertex shader:

#version 300 es
precision mediump float;

in vec3 position;
in vec2 uv;
in vec3 normal;

uniform mat4 transform;
uniform mat4 projection;

out f_norm;

void main(){
  //f_norm = normal;
  gl_Position = projection*transform*vec4(position,1.0);
}

Fragment Shader :

#version 300 es
precision mediump float;

in f_norm;

out vec4 Fragment;
void main(){
  Fragment = vec4(1.0);
}

I bind the VBOs using these lines :

GLES30.glBindAttribLocation(ProgramID,0,"position");
GLES30.glBindAttribLocation(ProgramID,1,"uv");
GLES30.glBindAttribLocation(ProgramID,2,"normal");

In the current form, the program works just fine, but if I uncomment this line : f_norm = normal, in the vertex shader, suddenly it uses uv coordinates as positions, even though they aren't used.

I know the data and the data mapping is fine : it works when I comment out the above line.

I know the binding is happening : it is very explicitly called, with the right values, when I check with the debugger.

I made sure that all the VBOs are properly enable and disable before and after the draw call.

I found an easy workaround ( specify layout(location = <VBO>) in front of the variables), but I'd like to know what's happening here, to get a more permanent fix.

\$\endgroup\$

1 Answer 1

3
\$\begingroup\$

Unreferenced variables are removed by compiler

What you are seeing is a kind of compilation optimisation (Though strictly speaking it is not considered an optimization).

When you declare inputs you need to use then or the compiler will remove them

Below all the variables are used and the code compiled looks like the source.

in vec3 A;
in vec3 B;
main () {
    gl_Position = A * B;
}

If you remove the reference to a declared variable the compiler seeing that it is not used will remove it completely.

Thus the following code that does not use B

in vec3 A;
in vec3 B;
main () {
    gl_Position = A;  // Not using B
}

Will be compiled as if the source looked like

in vec3 A;
// in vec3 B;  Compiler removed unreferenced variable B
main () {
    gl_Position = A;  // Not using B
}

When linking to a named variable the OpenGL implementation is not required to create an error if the name can not be found (it assumes that the index is pointing to an alias named "B" (the removed name)) .

What GLES30.glBindAttribLocation(pId,1,"B") does when the index is out of range is upto the OpenGL implementation and should be considered as undefined.

Fix?

There is no simple fix that I know of!

You can try an just include a dummy reference, as some implementations will consider the variable as referenced just to see it.

in vec3 A;
in vec3 B; 
main () {
    B;   // Cheap card and implementation might consider this a reference           
    gl_Position = A;
}

However very few implementation will do this and it becomes difficult to trick the better implementation.

\$\endgroup\$
5
  • \$\begingroup\$ I understand your explanation, but I don't understand why or how this behavior would lead to the deleted variable to overrite the used variable. My issue isn't that B doesn't exist, my issue is that A is interpreted as B if I remove B. \$\endgroup\$
    – Gyoo
    Jan 19 at 23:04
  • 2
    \$\begingroup\$ The behavior is undefined, there is no why! Different implementations, driver versions, etc.. may exhibit totally different undefined behaviours. You only use position thus UV and normal have been removed. You then bind attribute locations to index 1 uv and 2 normal outside the range of a single vertex in vec3 position. The resulting behaviour is undefined \$\endgroup\$
    – Blindman67
    Jan 20 at 0:05
  • \$\begingroup\$ Strange... I've never encountered this behavior before. Maybe it's a driver update screwing things up. \$\endgroup\$
    – Gyoo
    Jan 20 at 0:44
  • 1
    \$\begingroup\$ @Gyoo: Out of curiousity, what were you expecting out f_norm; in the Vertex Shader to contain, and what was in f_norm; supposed to indicate for the Fragment Shader, if they weren't given an explicit assignment to in vec3 normal? It sounds like you want it to be a null pointer, but is it used elsewhere that I'm not seeing in the code you provided? \$\endgroup\$ Jan 20 at 3:00
  • \$\begingroup\$ the shader is in developpement and I was testing that everything worked before I wrote a full shader. I intended to use f_norm to pass normals to the fragment shader later on. \$\endgroup\$
    – Gyoo
    Jan 20 at 18:24

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .