0
votes

I have a model made of cubes with 8 vertices only, and I am having issues with per vertex directional lighting. Instead of the entire model being lit at once, each cube seems to be lit separately like this.

This is my vertex shader:

layout(location = 0)in vec3 vp;
layout(location = 1)in vec3 color;
layout(location = 2)in vec3 normal;

out vec3 fColor;

uniform mat4 model;
uniform mat3 nm;
uniform mat3 partNM;
uniform mat4 modelPart;
uniform mat4 view;
uniform mat4 projection;

void main () {
    gl_Position = modelPart * vec4(vp, 1.0f);
    gl_Position = model * gl_Position;
    gl_Position = view * gl_Position;
    gl_Position = projection * gl_Position;

    mat3 normalMatrix =  partNM*nm;
    vec3 normalDirection = normalize(normalMatrix*normal);
    vec3 lightDirection = normalize(vec3(-1.0, 1.0, -1.0));

    vec3 diffuseReflection = clamp(dot(normalDirection, lightDirection),0.0,1.0);
    fColor = color+diffuseReflection;
}

and my fragment shader:

in vec3 fColor;
out vec4 frag_colour;

void main () {
    frag_colour = vec4(fColor.xyz,1.0);
}

This is the function I use to set the normal matrix:

void Shader::setNormalMatrix(string name,glm::mat4 matrix) {
    glm::mat3 nm = glm::transpose(glm::inverse(glm::mat3(matrix)));
    unsigned int location = glGetUniformLocation(program, name.c_str());
    glUniformMatrix3fv(location, 1, false, &nm[0][0]);
}

and the function which generates the vertices and normals for my cubes:

std::vector<float> Cube::createCube(float size,float x,float y,float z,float r, float g, float b) {
    VertexType points[8];

    points[0].x = (x*size)+0.0f;
    points[0].y = (y*size)+0.0f;
    points[0].z = (z*size)+size;
    points[0].nx = 0.577350; 
    points[0].ny = 0.577350;
    points[0].nz = -0.577350;
    points[0].r = r;
    points[0].g = g;
    points[0].b = b;

    points[1].x = (x*size)+size;
    points[1].y = (y*size)+0.0f;
    points[1].z = (z*size)+size;
    points[1].nx = -0.577350; 
    points[1].ny = 0.577350;
    points[1].nz = -0.577350;
    points[1].r = r;
    points[1].g = g;
    points[1].b = b;

    points[2].x = (x*size)+size;
    points[2].y = (y*size)+size;
    points[2].z = (z*size)+size;
    points[2].nx = -0.577350;
    points[2].ny = -0.577350;
    points[2].nz = -0.577350;
    points[2].r = r;
    points[2].g = g;
    points[2].b = b;

    points[3].x = (x*size)+0.0f;
    points[3].y = (y*size)+size;
    points[3].z = (z*size)+size;
    points[3].nx = 0.577350; 
    points[3].ny = -0.577350;
    points[3].nz = -0.577350;
    points[3].r = r;
    points[3].g = g;
    points[3].b = b;

    points[4].x = (x*size)+0.0f;
    points[4].y = (y*size)+0.0f;
    points[4].z = (z*size)+0.0f;
    points[4].nx = 0.577350; 
    points[4].ny = 0.577350;
    points[4].nz = 0.577350;
    points[4].r = r;
    points[4].g = g;
    points[4].b = b;

    points[5].x = (x*size)+size;
    points[5].y = (y*size)+0.0f;
    points[5].z = (z*size)+0.0f;
    points[5].nx = -0.577350; 
    points[5].ny = 0.577350;
    points[5].nz = 0.577350;
    points[5].r = r;
    points[5].g = g;
    points[5].b = b;

    points[6].x = (x*size)+size;
    points[6].y = (y*size)+size;
    points[6].z = (z*size)+0.0f;
    points[6].nx = -0.577350; 
    points[6].ny = -0.577350;
    points[6].nz = 0.577350;
    points[6].r = r;
    points[6].g = g;
    points[6].b = b;

    points[7].x = (x*size)+0.0f;
    points[7].y = (y*size)+size;
    points[7].z = (z*size)+0.0f;
    points[7].nx = 0.577350; 
    points[7].ny = -0.577350;
    points[7].nz = 0.577350;
    points[7].r = r;
    points[7].g = g;
    points[7].b = b;
    std::vector<float> rPoint;
    for(VertexType p:points) {
        rPoint.push_back(p.x);
        rPoint.push_back(p.y);
        rPoint.push_back(p.z);
        rPoint.push_back(p.r);
        rPoint.push_back(p.g);
        rPoint.push_back(p.b);
        rPoint.push_back(p.nx);
        rPoint.push_back(p.ny);
        rPoint.push_back(p.nz);
    }
    return rPoint;
}

The models are divided up into parts, which is why I have two normal and model matrices; one for the model as a whole, and one for an individual piece of the model. Is there a problem with my code, or do I need to use per-fragment lighting to fix this bug?

2
Where are your #version directives?genpfault
I have fixed the problem. I do not have a version directive. I would assume that I am using an opengl 4 version of glsl.jbills

2 Answers

3
votes

Your problem is the topology of your mesh. At the corner of a cube 3 faces meet. Each of these faces have a different normal. This creates a discontinuity in the normal's topology. Or to put it into simpler terms. You must use 3 vertices per corner, one for each face, with the face normal pointing into the right direction.

And while you're at it, you could remove those cube faces not being visible anyway.

0
votes

The reason is because you are rendering each cube as separate models. The shader will thus run once per model, in your case, once per cube. To solve this, you need render your entire model (your robot) as one model, with one set of vertices, rather than as a set of cubes.