I am trying to pass
out float texture_contribs[16]
from the vertex shader to the frament shader using glsl 3.3
However the values in the frament shader are always 0.0, no matter the value in the vertex shader.
Here is my vertex shader code:
uniform mat4 projectionMatrix;
uniform mat4 viewMatrix;
uniform mat4 modelMatrix;
uniform mat4 normalMatrix;
layout(location = 0) in vec4 in_position;
layout(location = 1) in vec4 in_colour;
layout(location = 2) in vec2 in_coord;
layout(location = 3) in vec3 in_normal;
layout(location = 4) in float texture_contributions[16];
out vec2 texcoord;
out vec4 pass_colour;
out float texture_contribs[16];
smooth out vec3 vNormal;
void main()
{
gl_Position = projectionMatrix * viewMatrix * modelMatrix * in_position;
texcoord = in_coord;
vec4 vRes = normalMatrix*vec4(in_normal, 0.0);
vNormal = vRes.xyz;
pass_colour = in_colour;
for (int i = 0; i < 16; i++)
{
texture_contribs[i] = texture_contributions[i];
}
}
and here is the fragment shader code:
uniform sampler2D texture[16];
in vec2 texcoord;
in vec4 pass_colour;
in float texture_contribs[16];
smooth in vec3 vNormal;
out vec4 out_colour;
struct SimpleDirectionalLight
{
vec3 vColor;
vec3 vDirection;
float fAmbientIntensity;
};
uniform SimpleDirectionalLight sunLight;
void main()
{
vec4 vTexColor = texture2D(texture[2], texcoord) * texture_contribs[2] + texture2D(texture[3], texcoord) * texture_contribs[3];
if(vTexColor.a < 0.1)
discard;
float fDiffuseIntensity = max(0.0, dot(normalize(vNormal), -sunLight.vDirection));
out_colour = vTexColor*pass_colour*vec4(sunLight.vColor*(sunLight.fAmbientIntensity+fDiffuseIntensity), 1.0);
}
I attempted splitting the array into individual variables and passing them separately and their values still disappear in the fragment shader.
const int gl_MaxVertexAttribs = 16; // Minimum: 16 Vertex Attribute Slots
GLuint max_vtx_attribs;
glGetIntegerv (GL_MAX_VERTEX_ATTRIBS, &max_vtx_attribs);
AMD is the only vendor I am aware of that offers more than the minimum of 16 attributes (they give 29-32 on some driver/hardware combinations). Intel, Apple, NVIDIA and Mesa all give you 16. If you want to write portable code, you should try and target no more than 16 vertex attributes. Otherwise, you have to write different code paths for different vendors, and that is no fun.
There are not many practical applications that require more than 16 per-vertex attributes, and ones that do generally rely on something better suited for storing large amounts of data such as Texture / Shader Storage Buffer Objects.
OpenGL 3.3 Core Profile Specification - 2.7 Vertex Specification - pp. 26
Vertex shaders (see section 2.11) access an array of 4-component generic vertex attributes. The first slot of this array is numbered 0, and the size of the array is specified by the implementation-dependent constant
GL_MAX_VERTEX_ATTRIBS
.
Each vertex attribute location in GLSL 3.3 is capable of storing a single vec4
, data types that are larger than vec4
(e.g. mat4
) will span multiple locations. Data types that are smaller than vec4
consume an entire location and this is where your shader starts to run into issues. You have declared a 16-element array of scalars, each of which is given its own sequential location beginning at 4. This means that the array occupies locations 4 - 19, but most implementations do not have 20 locations to hand out.
OpenGL 3.3 Core Profile Specification - 2.11.3 Vertex Attributes - pp. 55
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 will not count against the limit. In cases where the compiler and linker cannot make a conclusive determination, an attribute will be considered active. A program object will fail to link if the number of active vertex attributes exceeds
GL_MAX_VERTEX_ATTRIBS
.
The first 4 vertex attributes (0-3) are active, as are the 16 created by your scalar array. Your GLSL program (should) fail to link on any implementation that does not provide at least 20 vertex attributes. If it does not, then you have a non-compliant implementation.
You do not really need to consume 16 attribute slots to store all of your per-vertex data. If you replace this 16-element array of float
with a 4-element array of vec4
or a single mat4
, then you can store the same amount of data using only 4 attribute slots.
4 (in_position
, in_colour
, in_coord
, in_normal
) + 4 (texture_contributions
) = 8
This also vastly simplifies setting up vertex pointers, as you only need 8 of them instead of 20.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With