I’ve got a struct defined in my GLSL like so:
struct Rect {
float x;
float y;
float width;
float height;
};
Which I want to use as a uniform:
uniform Rect TextureRect;
So in my code I create an array of Uniforms:
_hudTexUniform = new[]
{
new Uniform(_hudShader, "TextureRect.x"),
new Uniform(_hudShader, "TextureRect.y"),
new Uniform(_hudShader, "TextureRect.width"),
new Uniform(_hudShader, "TextureRect.height"),
};
The constructor of which is defined as so:
public Uniform(ShaderProgram shaderProgram, string name)
{
if (shaderProgram == null) throw new ArgumentNullException("shaderProgram");
if (Regex.IsMatch(name, @"\s")) throw new ArgumentException("Cannot contain white space.", "name");
if (name.StartsWith("gl_")) throw new ArgumentException("Cannot start with reserved prefix \"gl_\"", "name");
Location = shaderProgram.GetUniformLocation(name);
if (Location < 0) throw new ArgumentException("Name does not correspond to an active uniform variable in program", "name");
}
x and y work perfectly, but when it gets to width an exception is thrown (“Name does not correspond…”), i.e., glGetUniformLocation is returning -1.
I don’t see any typos, and I just checked the GLSL 4.1 spec, and it doesn’t look like “width” nor “height” are keywords….so why else would this be failing?
glGetUniformLocationis allowed, as a convenience to video drivers, to return -1 if the requested uniform isn’t actually being used by the shader (dead-stripped, for example). This isn’t an error—changes to that uniform viaglUniform*will be ignored. But that means that you need to treat-1as a valid uniform location.Incidentally, this is probably a good thing for decoupling shaders from your rendering—your code can simply throw all relevant values at the shader and not worry about which ones the shader actually cares about. It also means that you can test to see if a shader actually uses a value and not compute it in the first place if it’s not needed.