Darinth
Darinth

Reputation: 510

Getting a constant from a GLSL shader

I have a shader written in GLSL with an array of structs for holding light data. I use a constant to declare the array size, as is good practice. Let's say this variable is declared as

const int NUM_POINT_LIGHTS = 100;

How can I use C++ to pull this data out of the shader, so that my C++ program knows exactly how many lights it has available to it? I've tried declaring it as

const uniform int NUM_POINT_LIGHTS = 100;

As expected, this didn't work (though oddly enough, it appears as though the uniform specification simply overrode the const specification, as the OpenGL complained that I was initializing an array with a non-const value). I also tried

const int NUM_POINT_LIGHTS = 100;
uniform numPointLights = NUM_POINT_LIGHTS;

This would work, except for the fact that GLSL optimizes away unused uniforms so I have to track glsl into thinking the uniform is used somehow in order to be able to get a hold of the data. I've not been able to find any other method to query a program to get a constant value. Does anybody have any ideas how I might be able to pull a constant out of a shader so my program to get information that is functionally encoded in the shader for it's use?

Upvotes: 6

Views: 3378

Answers (2)

Reto Koradi
Reto Koradi

Reputation: 54592

I don't think you can directly get the value of the constant. However, I figure you must use the value of the constant, most likely as the size of a uniform array. If that's the case, you can get the size of the uniform array, which indirectly gets you the value of the constant.

Say your shader contains something like this:

const int NUM_POINT_LIGHTS = 100;
uniform vec3 LightPositions[NUM_POINT_LIGHTS];

Then you can first get the index of this uniform:

const GLchar* uniformName = "LightPositions";
GLuint uniformIdx = 0;
glGetUniformIndices(program, 1, &uniformName, &uniformIdx);

Using this index, you can then retrieve attributes of this uniform:

const int nameLen = strlen("LightPositions") + 1;
const GLchar name[nameLen];
GLint uniformSize = 0;
GLenum uniformType = GL_NONE;
glGetActiveUniform(program, uniformIdx, nameLen, NULL,
                   &uniformSize, &uniformType, name);

uniformSize should then be the value of the NUM_POINT_LIGHTS constant. Note that I haven't tried this, but I hope I got the arguments right based on the documentation.

A somewhat ugly but possibly very practical solution is of course to parse the value out of the shader source code. Since you need to read it in anyway before passing it to glShaderSource(), picking out the constant value should be easy enough.

Yet another option, if your main goal is to avoid having the constant in multiple places, is to define it in your C++ code, and add the constant definition to the shader code dynamically after reading in the shader code, and before passing it go glShaderSource().

Upvotes: 9

BlamKiwi
BlamKiwi

Reputation: 2193

You can't just query a constant from a GLSL program. No such thing is defined in the GLSL spec.

Uniform Buffer Objects might be a way to get around the issue of uniforms being optimized out. https://www.opengl.org/wiki/Uniform_Buffer_Object

Upvotes: 0

Related Questions