0
votes

I have a shader which has multiple lights, and I would like to get the uniform location of each of the lights' attributes without having to manually type it out for every light. However, as glGetUniformLocation finds the uniform using a string, I cannot do that.

for (unsigned int i = 0; i < MAX_LIGHTS; ++i) {
    shaderParameters[PHONG * U_TOTAL + U_LIGHT0_ON + n] = glGetUniformLocation(shaderProgramID[PHONG], "lights[n].on");
    shaderParameters[PHONG * U_TOTAL + U_LIGHT0_TYPE + n] = glGetUniformLocation(shaderProgramID[PHONG], "lights[n].type");
    shaderParameters[PHONG * U_TOTAL + U_LIGHT0_POSITION + n] = glGetUniformLocation(shaderProgramID[PHONG], "lights[n].position_cameraspace");
    shaderParameters[PHONG * U_TOTAL + U_LIGHT0_COLOR + n] = glGetUniformLocation(shaderProgramID[PHONG], "lights[n].color");
    shaderParameters[PHONG * U_TOTAL + U_LIGHT0_POWER + n] = glGetUniformLocation(shaderProgramID[PHONG], "lights[n].power");
    shaderParameters[PHONG * U_TOTAL + U_LIGHT0_KC + n] = glGetUniformLocation(shaderProgramID[PHONG], "lights[n].kC");
    shaderParameters[PHONG * U_TOTAL + U_LIGHT0_KL + n] = glGetUniformLocation(shaderProgramID[PHONG], "lights[n].kL");
    shaderParameters[PHONG * U_TOTAL + U_LIGHT0_KQ + n] = glGetUniformLocation(shaderProgramID[PHONG], "lights[n].kQ");
    shaderParameters[PHONG * U_TOTAL + U_LIGHT0_SPOTDIRECTION + n] = glGetUniformLocation(shaderProgramID[PHONG], "lights[n].spotDirection");
    shaderParameters[PHONG * U_TOTAL + U_LIGHT0_COSCUTOFF + n] = glGetUniformLocation(shaderProgramID[PHONG], "lights[n].cosCutoff");
    shaderParameters[PHONG * U_TOTAL + U_LIGHT0_COSINNER + n] = glGetUniformLocation(shaderProgramID[PHONG], "lights[n].cosInner");
    shaderParameters[PHONG * U_TOTAL + U_LIGHT0_EXPONENT + n] = glGetUniformLocation(shaderProgramID[PHONG], "lights[n].exponent");
}

For example, since "lights[n].on" is a const char*, glGetUniformLocation cannot find it as n is not a number. How would I make it such that I can just loop through like that? Thanks in advance.

2
generate the strings - BeyelerStudios

2 Answers

1
votes

You simply need to construct the string dynamically as needed.

//Helper function that takes a `string`.
GLint GetUniformLocation(GLuint program​, const std::string &name)
{
  return glGetUniformLocation(program​, name.c_str());
}

for (unsigned int i = 0; i < MAX_LIGHTS; ++i) {
    shaderParameters[PHONG * U_TOTAL + U_LIGHT0_ON + n] =
      GetUniformLocation(shaderProgramID[PHONG], "lights[" + std::tostring(i) + "].on");
    //And so forth.
}

Note: the above assumes you're using a recent version of C++.

However, as 246Nt suggested, using UBOs with std140 layout would make changing this data so much easier. But, if you're dead-set on using non-block uniforms, you could employ explicit uniform locations, if you have GL 4.3 or ARB_explicit_uniform_location. This way, you don't have to query the locations at all; you know what they are because you set those locations in the shader. And the locations of each component of the array/struct will be allocated sequentially for each sub-member.

0
votes

I'd recommend using UBOs : https://www.opengl.org/wiki/Uniform_Buffer_Object

This way you essentially just 'send' all the light params at once, via a single uniform block.