I've been trying to develop shaders that would allow me to easily display text on screen using a font texture. I've previously written shaders that simply drew the text on screen and I passed the exact coordinates for the vertices and UV coordinates to the shaders. With my new shaders, I'm trying to pass just a single point for each letter, representing the bottom left corner each letter, as well as a single point for the UV coordinate of the letter, representing its location on the font texture. I then use a geometry shader to generate the triangles and UV coordinates necessary to draw the letters. Here is my code for the shaders:
Vertex Shader:
#version 330
layout(location = 0) in vec2 vertexPosition;
layout(location = 1) in vec2 vertexUV;
layout(location = 2) in float textSize;
uniform unsigned int textureX;
uniform unsigned int textureY;
out VertexData
{
vec2 uv;
float textSize;
} outputData;
void main()
{
// Represents the bottom left corner
gl_Position = vec4(vertexPosition, 0.0f, 1.0f);
// Convert the UV coordinates from [0, textureX - 1] to [0, 1]
outputData.uv = vertexUV / vec2(textureX, textureY);
outputData.textSize = textSize;
}
Geometry Shader:
#version 330
layout(points) in;
layout(triangle_strip, max_vertices = 6) out;
uniform unsigned int textureX;
uniform unsigned int textureY;
in VertexData
{
vec2 uv;
float textSize;
} inputData[];
out FragmentData
{
vec2 uv;
} outputData;
void main()
{
float textureWidth = 1.0f / textureX;
float textureHeight = 1.0f / textureY;
// Calculate the vertices
vec2 brCorner = vec2(gl_in[0].gl_Position) + vec2(inputData[0].textSize, 0.0f);
vec2 tlCorner = vec2(gl_in[0].gl_Position) + vec2(0.0f, inputData[0].textSize);
vec2 trCorner = vec2(gl_in[0].gl_Position) + vec2(inputData[0].textSize, inputData[0].textSize);
vec2 uvBR = inputData[0].uv + vec2(textureWidth, 0.0f);
vec2 uvTL = inputData[0].uv + vec2(0.0f, textureHeight);
vec2 uvTR = inputData[0].uv + vec2(textureWidth, textureHeight);
gl_Position = vec4(tlCorner, 0.0f, 1.0f);
outputData.uv = uvTL;
EmitVertex();
gl_Position = gl_in[0].gl_Position;
outputData.uv = inputData[0].uv;
EmitVertex();
gl_Position = vec4(trCorner, 0.0f, 1.0f);
outputData.uv = uvTR;
EmitVertex();
EndPrimitive();
gl_Position = gl_in[0].gl_Position;
outputData.uv = inputData[0].uv;
EmitVertex();
gl_Position = vec4(brCorner, 0.0f, 1.0f);
outputData.uv = uvBR;
EmitVertex();
gl_Position = vec4(trCorner, 0.0f, 1.0f);
outputData.uv = uvTR;
EmitVertex();
EndPrimitive();
}
Fragment Shader:
#version 330 core
in FragData
{
vec2 uv;
} inputData;
out vec4 color;
uniform sampler2D textureSampler;
void main()
{
color = texture2D(textureSampler, inputData.uv);
}
When I call glGetUniformLocation for the textureSampler uniform in my fragment shader, I get a valid uniform location back. However, when I call glGetUniformLocation for textureX and textureY, glGetUniformLocation returns -1. When I searched for what could cause this, the main cause of this issue is usually the compiler optimizing the variable out as it's not used. I don't believe this to be true in my case, but I have no idea what could be causing glGetUniformLocation to return -1 for this.
Edit: After reading Andon M. Coleman's excellent answer on how active uniforms are determined, I discovered the issue. The name of the struct the geometry shader outputs and the name of the struct the fragment shader accepts are different-
Geometry Shader:
out FragmentData
{
vec2 uv;
} outputData;
Fragment Shader:
in FragData
{
vec2 uv;
} inputData;
After changing the structs to share the same name, I am able to get a valid uniform location back.
glUniformBlockBinding
. \$\endgroup\$textureX
andtextureY
uniform take, the only scenario in which they are not linked to an active code path would be if you did not attach your geometry shader. The easiest way to see if this is the culprit, would be to add the uniforms to your fragment shader and try sampling your texture usingvec2 (textureX, textureY)
\$\endgroup\$