I recently learned how to load a model to openGL using assimp, but I am having trouble figuring out how to do lighting calculations on this model. Previously with my own created objects I would set the normals manually and pass them to the shader as attributes. Then I would use one diffuse and one specular texture passed as uniforms for lighting.

I'm trying to do the same with a model, but I can't seem to get it to behave correctly. When I use my own objects everything works normally, but when I try to draw the model some weird lighting occurs.

Here's how the model should look: enter image description here

But mine looks like this:

enter image description here

What confuses me in particular is that assimp loads both normal vertices and normal textures. I'm not sure what the difference between them is or if there is more about model loading that I've yet to learn, which is entirely possible since I don't know much about heightmaps and other things yet.

Anyway, here's what I'm doing for calculations:

void main() 
    vec3 normal = normalize(Normal);
    vec3 viewDir = normalize(viewPos - fragPos);

    vec3 result;

    for (int j = 0; j < sizeModels; j++)
        result += CalcDirLight(DirLights, normal, viewDir, models[j]);

    FragColor = vec4(result, 1.0);

vec3 CalcDirLight(DirLight light, vec3 normal, vec3 viewDir, Material textures)
    vec3 lightDir = normalize(-light.direction);
    // diffuse shading
    float diff = max(dot(normal, lightDir), 0.0);
    // specular shading
    vec3 reflectDir = reflect(-lightDir, normal);
    float spec = pow(max(dot(viewDir, reflectDir), 0.0), textures.shininess);
    // combine results
    vec3 ambient = light.ambient * vec3(texture(textures.diffuse, Tex));
    vec3 diffuse = light.diffuse * diff * vec3(texture(textures.diffuse, Tex));
    vec3 specular = light.specular * spec * vec3(texture(textures.specular, Tex));
    return (ambient + diffuse + specular);

Notice that I'm providing my own diffuse values to the DirLight struct. The Material struct is what contains the diffuse and specular textures, as well as a shininess float.

For reference I am following guides from this site: https://learnopengl.com/

Any help would be appreciated!

  • \$\begingroup\$ It's unusual to loop over multiple sets of materials and sum their colour contributions for a single fragment. Can you clarify why you're doing this? It doesn't look like you're blending between different materials based on some kind of interpolation factor, so I'm unsure what the aim is here. \$\endgroup\$
    – DMGregory
    Commented May 7, 2020 at 14:43
  • \$\begingroup\$ I'm not exactly sure what you mean by "blending between different materials based on some kind of interpolation factor". I am looping over multiple materials since I loaded the model with multiple meshes, and each has their own textures which are parts of the whole. The idea is to do the same thing I was doing to my own object but with the textures obtained with assimp. \$\endgroup\$
    – Julk
    Commented May 8, 2020 at 5:35
  • \$\begingroup\$ You'll likely want to draw each mesh with its own texture, not with all of them summed together. \$\endgroup\$
    – DMGregory
    Commented May 8, 2020 at 10:46
  • \$\begingroup\$ That's actually what I was doing with a simpler shader before trying this out. I figured I could make the process more efficient this way, but it doesn't really seem to be that beneficial. I went back and did the calculations the way you said and it seems to work perfectly. Thank you so much! It seems I still have much to learn about the shader process. \$\endgroup\$
    – Julk
    Commented May 9, 2020 at 3:20
  • \$\begingroup\$ Want to share your solution as an Answer below? \$\endgroup\$
    – DMGregory
    Commented May 9, 2020 at 3:23

1 Answer 1


Turns out the idea of adding every mesh's texture into a single fragment was unnecessary. Each individual mesh already contained its own textures, so drawing them individually allows for the same result.

Changes on the fragment shader:

void main()
    vec3 viewDir = normalize(viewPos - FragPos);
    vec3 Normalized = normalize(Normal);

    // Now a single result. Function no longer needs the fourth parameter since it just accesses the single uniform struct instead of an array of structs.
    vec3 result = CalcDirLight(DirLights, Normalized, viewDir);

    FragColor = vec4(result, 1.0);

I am still unsure how this compares to my original idea performance-wise, but this is definitely makes more sense logically.


You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .