4

I'm trying to set the values of the individual fields of structs in an array. The problem is that in the shader, every single field of the struct has the value 0 assigned to it.

Shader:

struct Light
{
    vec3 position;
    vec3 color;
    float ambient;
    float diffuse;
    float specular;
    float exponent;
};

uniform Light lights[8];

C++:

struct Light
{
    vec3 position;
    vec3 color;
    float ambient;
    float diffuse;
    float specular;
    float exponent;
};

...

std::vector<Light> activeLights;

Light l;
l.position = vec3(-50.0f, 50.0f, 50.0f);
l.color = vec3(1.0f, 1.0f, 1.0f);
l.ambient = 0.15f;
l.diffuse = 0.6f;
l.specular = 0.25f;
l.exponent = 8.0f;
activeLights.push_back(l);

...

for (int i = 0; i < activeLights.size(); i++)
{
    glUniform3f(glGetUniformLocation(program, "lights[i].position"), 
                    activeLights[i].position.x,
                    activeLights[i].position.y,
                    activeLights[i].position.z
    );
    glUniform3f(glGetUniformLocation(program, "lights[i].color"),
                    activeLights[i].color.r,
                    activeLights[i].color.g,
                    activeLights[i].color.b
    );
    glUniform1f(glGetUniformLocation(program, "lights[i].ambient"), activeLights[i].ambient);
    glUniform1f(glGetUniformLocation(program, "lights[i].diffuse"), activeLights[i].diffuse);
    glUniform1f(glGetUniformLocation(program, "lights[i].specular"), activeLights[i].specular);
    glUniform1f(glGetUniformLocation(program, "lights[i].exponent"), activeLights[i].exponent);
}

I checked the values on the c++ side multiple times in the debugger, everything's ok there.

Any ideas?

1
  • 4
    "lights[i].position": that's a string containing exactly what is written there. i is not magically replaced by the number. If you want to replace i with the corresponding number, you'll have to use an std::stringstream or snprintf or something similar. Commented Jan 27, 2019 at 20:33

1 Answer 1

6
"lights[i].position"

Unlike some scripting languages, C++ has no mechanism to apply code to a string literal. As such, "lights[i].position" is always exactly that string. 'i' is not recognized as being anything special; it is the character 'i'.

What you really want to do is generate a string based on the variable i. Which can be done easily enough:

std::ostringstream strm;
strm << "lights[" << i << "]";
std::string light = strm.str();

There are more efficient ways to do this, but this is the easiest way in C++. In any case, if performance really mattered, you wouldn't be querying uniform locations at runtime.

Now, you have to generate a string for every single uniform member access, then use that string to access that uniform member. So, for each access, you have to do this:

    std::string str = light + ".position";
    glUniform3f(glGetUniformLocation(program, str.c_str()), 
                    activeLights[i].position.x,
                    activeLights[i].position.y,
                    activeLights[i].position.z
    );

You can reuse str, rather than defining new strings.

Sign up to request clarification or add additional context in comments.

1 Comment

Right, thank you very much! I thought of the most complicated solutions but i did not see that simple mistake^^

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.