I'm trying to make a glsl shader that can turn off texturing and/or coloring (I want to be able to tint a texture). I can disable an attribute by doing glDisableVertexAttribArray(x)
, but I'm wondering what the values will look like in the shader. will they be 0
?
Also, is there a way to check if an attribute is enabled inside the shader code? I thought of a uniform (probably int
) to store flags and test them in the shader, but that would require if
statements and I think I've heard it's not recommended.
Here are my shaders in case you want to refer to them, I currently am working on the int
flag I was talking about.
Vertex shader:
#version 450
layout(location=0) uniform mat4 projection_matrix;
layout(location=1) uniform mat4 view_matrix;
layout(location=2) uniform mat4 model_matrix;
// 0b0000 0000 0000 0 unused
// 0 textures
// 0 colors
// 0 2d/3d
layout(location=3) uniform uint mode;
layout(location=0) in vec4 vert_tex_coord;
layout(location=1) in vec4 vert_color;
layout(location=2) in vec3 vert_2_position;
layout(location=3) in vec3 vert_3_position;
out vec4 vert_frag_color;
out vec2 vert_frag_tex_coord;
vec4 transform(vec4 v)
{
return projection_matrix * view_matrix * model_matrix * v;
}
void main()
{
if ((mode & 1) > 0)
{
gl_Position = transform(vec4(vert_3_position, 1.0));
}
else
{
gl_Position = transform(vec4(vert_2_position, 0.0, 1.0));
}
if ((mode & 2) > 0)
{
vert_frag_color = vert_color;
}
if ((mode) & 4) > 0)
{
vert_frag_tex_coord = vert_tex_coord;
}
}
Fragment shader:
#version 450
layout(location=3) uniform uint mode;
uniform sampler2D texture_0;
in vec4 vert_frag_color;
out vec2 vert_frag_tex_coord;
out vec4 frag_color;
void main()
{
if ((mode & 2) > 1)
{
frag_color = vert_frag_color;
}
if ((mode) & 4) > 1)
{
frag_color = texture(texture_0, vert_frag_tex_coord);
}
}
I can disable an attribute by doing
glDisableVertexAttribArray(x)
, but I'm wondering what the values will look like in the shader. will they be0
?
No, actually, the "current" value of each attribute is part of the global GL state. You can set the value for each attribute where the array is disabled via the glVertexAttrib*()
family of functions. There is just a minor twist: whenever you draw something with some attribute array enabled and later disable the attribute array, the current value of that attribute will be undefined, so you have to re-specify it via glVertexAttrib*()
again.
The following construct in your code does not make sense at all:
if ((mode & 1) > 1) { gl_Position = transform(vec4(vert_3_position, 1.0)); } else { gl_Position = transform(vec4(vert_2_position, 0.0, 1.0)); }
mode & 1
will either be 1 or 0, so the comparision > 1 will always be false. However, that mode is not needed at all. The GL will automatically extend input attribute vectors to the form (0, 0, 0, 1) if not all elements are specified. So it will be enough to use
in vec4 vert_position;
// ...
gl_Position = transform (vert_position);
and you can just specify 1, 2, 3 or 4 components in the glVertexAttribPointer()
call and it will work as expected. The idiom in vec3 position; /* ... */ matrix * vec4(position, 1.0);
is commonly used in tutorials, but is not needed at all. It might be argued that it makes it more explicit what is actually going on, though.
Also, is there a way to check if an attribute is enabled inside the shader code?
No, there isn't. There is always some current value for every attribute. If that came from an array or not is totally irrelevant for the shader.
I thought of a uniform (probably
int
) to store flags and test them in the shader, but that would requireif
statements and I think I've heard it's not recommended.
Well, a branch based on a uniform value will still result in uniform control flow, so it is not he worst thing that could happen. But it will not be free of overhead. If it is worth it is something which depends on the actual requirements on your scene. It might be better using different shaders and switching between them. But that all depends on how many such state switches would occur, and how many work each shader inbetween the switches would do - and also, how many combinations of shaders you would need. That is something you should benchmark/profile, preferrably across different GL implementations.