Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 338
Darinth Avatar asked Oct 24 '14 03:10

Darinth


1 Answers

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().

like image 59
Reto Koradi Avatar answered Sep 27 '22 20:09

Reto Koradi