0
votes

I'm having an issue drawing multiple point lights in my scene. I am working on a simple maze-style game in OpenGL, where the maze is randomly generated. Each "room" in the maze is represented by a Room struct, like so:

struct Room
{
    int x, z;
    bool already_visited, n, s, e, w;
    GLuint vertex_buffer, texture, uv_buffer, normal_buffer;
    std::vector<glm::vec3>vertices, normals;
    std::vector<glm::vec2>uvs;
    glm::vec3 light_pos; //Stores the position of a light in the room
};

Each room has a light in it, the position of this light is stored in light_pos. This light is used in a simple per-vertex shader, like so:

layout(location = 0) in vec3 pos;
layout(location = 1) in vec2 uv_coords;
layout(location = 2) in vec3 normal;
uniform mat4 mvpMatrix;
uniform mat4 mvMatrix;
uniform vec3 lightpos;
out vec2 vs_uv;
out vec3 vs_normal;
out vec3 color;
void main()
{
    gl_Position = mvpMatrix * vec4(pos,1.0);
    vs_normal = normal;
    vs_uv = uv_coords;
    vec3 lightVector = normalize(lightpos - pos);
    float diffuse = clamp(dot(normal,lightVector),0.0,1.0);
    color = vec3(diffuse,diffuse,diffuse);
}

My fragment shader looks like this (ignore the "vs_normal", it is unused for now):

in vec2 vs_uv;
in vec3 vs_normal;
in vec3 color;
uniform sampler2D tex;
out vec4 frag_color;

void main()
{
    frag_color = vec4(color,1.0) * texture(tex,vs_uv).rgba;
}

And my drawing code looks like this:

mat4 mvMatrix = view_matrix*model_matrix;
mat4 mvpMatrix = projection_matrix * mvMatrix;
glBindVertexArray(vertexBufferObjectID);
glUseProgram(shaderProgram);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glEnableVertexAttribArray(2);
for (int x = 0; x < NUM_ROOMS_X; x++)
{
   for (int z = 0; z < NUM_ROOMS_Z; z++)
   {
      //int x = int(std::round(position.x / ROOM_SIZE_X_MAX));
      //int z = int(std::round(position.z / ROOM_SIZE_Z_MAX));
      Room rm = room_array[x][z];
      glBindBuffer(GL_ARRAY_BUFFER, rm.vertex_buffer);
      glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*) 0);

      glBindBuffer(GL_ARRAY_BUFFER, rm.uv_buffer);
      glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, (void*) 0);

      glBindBuffer(GL_ARRAY_BUFFER, rm.normal_buffer);
      glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 0, (void*) 0);

      glUniformMatrix4fv(mvpMatrixID, 1, GL_FALSE, &mvpMatrix[0][0]);
      glUniformMatrix4fv(mvMatrixID, 1, GL_FALSE, &mvMatrix[0][0]);
      glUniform3fv(light_ID, 3, &rm.light_pos[0]); //Here is where I'm setting the new light position. It looks like this is ignored

      glActiveTexture(GL_TEXTURE0);
      glBindTexture(GL_TEXTURE_2D, rm.texture);
      glUniform1i(texture_ID, 0);

      glDrawArrays(GL_QUADS, 0, rm.vertices.size());
   }
}
glUseProgram(0);
glBindVertexArray(0);
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
glDisableVertexAttribArray(2);
glBindTexture(GL_TEXTURE_2D, 0);

However, here is what the result looks like (I've modified my drawing code to draw a box where each light is located, and I've circled the room at position (0,0)):

http://imgur.com/w4uPMD6

As you can see, it looks like only the light at position (0,0) affects any of the rooms on the map, the other lights are simply ignored. I know that the lights are positioned correctly, because the boxes I use to show the positions are correct. I think even though I'm setting the new light_pos, it isn't going through for some reason. Any ideas?

2

2 Answers

0
votes

One thing that your are doing, which is not very common, is to pass the light position as a vertex attribute. Optimally, you should pass it to the shader as a uniform variable, just as you do with the matrices. But I doubt that is the problem here.

I believe your problem is that you are doing the light calculations in different spaces. The vertexes of the surfaces that you draw are in object/model space, while I'm guessing, your light is located at a point defined in world space. Try multiplying your light position by the inverse of the model matrix you are applying to the vertexes. I'm not familiar with GLM, but I figure there must be an inverse() function in it:

vec3 light_pos_object_space = inverse(model_matrix) * rm.light_pos;
glVertexAttrib3fv(light_ID, &light_pos_object_space[0]);
0
votes

Figured out my problem. I was calling this function:

glUniform3fv(light_ID, 3, &rm.light_pos[0]);

When I should have been calling this:

glUniform3fv(light_ID, 1, &rm.light_pos[0]);