0
\$\begingroup\$

I am encountering an issue when using a normal map with directional and/or point lighting. Without using the lighting, I am able to render the object fine. When any amount of lighting is applied, it causes the object to flicker (as shown below).

The lighting also works fine when I am not using a normal map. I believe this is an issue with the shader code. The shader code does allow for more than one light source at a time. However, even if I just use one light source (e.g. one directional light) and the normal mapping, the flickering occurs.

enter image description here

Full Repo: https://github.com/paulburgess1357/ExtraLifeEngine

Vertex Code:

#version 330 core
#define MAXIMUM_DIR_LIGHTS 2
#define MAXIMUM_POINT_LIGHTS 2

struct DirectionalLight {
    vec3 direction;
};

struct PointLight {
    vec3 position;
    
    float constant;
    float linear;
    float quadratic;
};

layout (location = 0) in vec3 model_position;
layout (location = 1) in vec3 model_normals;
layout (location = 2) in vec2 tex_coords;
layout (location = 3) in vec3 in_tangent;
layout (location = 4) in vec3 in_bitangent;

// Global uniforms
layout (std140) uniform uniform_matrices {
    mat4 projection_matrix;
    mat4 view_matrix;
};

layout (std140) uniform uniform_camera_world_position{
    vec3 camera_world_position;
};

uniform int active_dirlight_qty; // Set to -1 during shader initialization
uniform DirectionalLight dirlight[MAXIMUM_DIR_LIGHTS];

uniform int active_pointlight_qty; // Set to -1 during shader initialization
uniform PointLight pointlight[MAXIMUM_POINT_LIGHTS];

// Input 
uniform mat4 model_matrix;
uniform mat3 normal_matrix;

// Output
out PointLight tangent_pointlights[MAXIMUM_POINT_LIGHTS];
out DirectionalLight tangent_dirlights[MAXIMUM_DIR_LIGHTS];

out vec3 tangent_camera_position;
out vec3 tangent_fragment_position;
out vec2 fragment_tex_coords;

// Function Definitions
mat3 calc_tbn_matrix(mat3 normal_matrix, vec3 model_normals, vec3 tangent_vec);
PointLight convert_pointlight_to_tangent_space(PointLight pointlight, mat3 tbn_matrix);
DirectionalLight convert_dirlight_to_tangent_space(DirectionalLight dirlight, mat3 tbn_matrix);

void main(){
   
    // TBN Matrix
    mat3 tbn_matrix = calc_tbn_matrix(normal_matrix, model_normals, in_tangent);

    // Calc fragment_position for gl_Position and tangent_fragment_position
    vec3 fragment_position = vec3(model_matrix * vec4(model_position, 1.0)); // World space 

    // Convert Pointlights to Tangent Space
    for(int i = 0; i < active_pointlight_qty; i++){
        tangent_pointlights[i] = convert_pointlight_to_tangent_space(pointlight[i], tbn_matrix);
    }

    // Convert Directional Lights to Tangent Space
    for(int i = 0; i < active_dirlight_qty; i++){
        tangent_dirlights[i] = convert_dirlight_to_tangent_space(dirlight[i], tbn_matrix);
    }          

    // Output (tangent_pointlights and tangent_dirlights are also output)
    fragment_tex_coords = tex_coords;
    tangent_camera_position = tbn_matrix * camera_world_position;
    tangent_fragment_position = tbn_matrix * fragment_position;
    gl_Position = projection_matrix * view_matrix * vec4(fragment_position, 1.0);
    
}

mat3 calc_tbn_matrix(mat3 normal_matrix, vec3 model_normals, vec3 tangent_vec){

    vec3 t = normalize(normal_matrix * tangent_vec);
    vec3 n = normalize(normal_matrix * model_normals);    
    t = normalize(t - dot(t, n) * n);
    vec3 b = cross(n, t);
    mat3 tbn_matrix = transpose(mat3(t, b, n));

    return tbn_matrix;

};

PointLight convert_pointlight_to_tangent_space(PointLight pointlight, mat3 tbn_matrix){
    pointlight.position = normalize(tbn_matrix * pointlight.position);
    return pointlight;

};

DirectionalLight convert_dirlight_to_tangent_space(DirectionalLight dirlight, mat3 tbn_matrix){
    dirlight.direction = normalize(tbn_matrix * dirlight.direction);
    return dirlight;
};

Fragment Code

#version 330 core
#define MAXIMUM_DIR_LIGHTS 2
#define MAXIMUM_POINT_LIGHTS 2

struct DiffuseMaterial {
    sampler2D m_sampler;
};

struct SpecularMaterial {
    sampler2D m_sampler;
    float m_shininess;
};

struct NormalMaterial {
    sampler2D m_sampler;
};

struct DirectionalLight {
    vec3 direction;
};

struct SceneLight {
    vec3 ambient;
    vec3 diffuse;
    vec3 specular; 
};

struct PointLight {
    vec3 position;
    
    float constant;
    float linear;
    float quadratic;
};

// Shader Uniforms
// uniform int active_diffuse_qty;
uniform DiffuseMaterial diffuse_material;

// uniform int active_specular_qty;
uniform SpecularMaterial specular_material;

// uniform int active_normal_qty
uniform NormalMaterial normal_material;

uniform SceneLight scenelight;

uniform int active_dirlight_qty; // Set to -1 during shader initialization
uniform int active_pointlight_qty; // Set to -1 during shader initialization

in DirectionalLight tangent_dirlights[MAXIMUM_DIR_LIGHTS];
in PointLight tangent_pointlights[MAXIMUM_POINT_LIGHTS];

in vec3 tangent_camera_position;
in vec3 tangent_fragment_position;
in vec2 fragment_tex_coords;

// Output
out vec4 fragment_color;

// Function Definitions
vec3 calc_directional_light(DirectionalLight dirlight, 
                            DiffuseMaterial diffuse_material,
                            SpecularMaterial specular_material,
                            SceneLight scenelight, 
                            vec3 normalized_frag_model_normals, 
                            vec3 view_direction, 
                            vec2 fragment_tex_coords);

vec3 calc_point_light(PointLight pointlight, 
                      DiffuseMaterial diffuse_material,
                      SpecularMaterial specular_material,
                      SceneLight scenelight,                       
                      vec3 normalized_frag_model_normals, 
                      vec3 view_direction, 
                      vec2 fragment_tex_coords,
                      vec3 fragment_position);

// Shader
void main() {
    
    // Normal map to normal vector; Transform to range -1, 1
    vec3 normalized_frag_model_normals = normalize(texture(normal_material.m_sampler, fragment_tex_coords).rgb);
    
    // Convert normal to tangent space
    normalized_frag_model_normals = normalize(normalized_frag_model_normals * 2 - 1); 
    vec3 tangent_view_direction = normalize(tangent_camera_position - tangent_fragment_position);
    
    // Lighting
    vec3 result = vec3(0.0f);
    
    // Directional
    for(int i = 0; i <= active_dirlight_qty; i++) {
        result += calc_directional_light(tangent_dirlights[i], diffuse_material, specular_material, scenelight, normalized_frag_model_normals, tangent_view_direction, fragment_tex_coords);
    }

    // Point (active pointlight qty set to -1 during shader compilation)
    for(int i = 0; i <= active_pointlight_qty; i++){
        result += calc_point_light(tangent_pointlights[i], diffuse_material, specular_material, scenelight, normalized_frag_model_normals, tangent_view_direction, fragment_tex_coords, tangent_fragment_position);
    }

    if(result.x == 0.0f && result.y==0.0f && result.z==0.0f){
       result = scenelight.ambient  * vec3(texture(diffuse_material.m_sampler, fragment_tex_coords)); 
    }
    
    fragment_color = vec4(result, 1.0);
};

// Function Definitions
vec3 calc_directional_light(DirectionalLight dirlight, 
                            DiffuseMaterial diffuse_material,
                            SpecularMaterial specular_material,
                            SceneLight scenelight, 
                            vec3 normalized_frag_model_normals, 
                            vec3 view_direction, 
                            vec2 fragment_tex_coords){
    
    vec3 light_direction = normalize(dirlight.direction);
    vec3 halfway_btwn_view_and_light_dir = normalize(light_direction + view_direction);

    // Ambient
    vec3 ambient = scenelight.ambient * vec3(texture(diffuse_material.m_sampler, fragment_tex_coords));

    // Diffuse
    float diffuse_impact = max(dot(normalized_frag_model_normals, light_direction), 0.0);
    vec3 diffuse = scenelight.diffuse  * diffuse_impact * vec3(texture(diffuse_material.m_sampler, fragment_tex_coords));

    // Specular
    float specular_impact = pow(max(dot(normalized_frag_model_normals, halfway_btwn_view_and_light_dir), 0.0), specular_material.m_shininess);
    vec3 specular = scenelight.specular * specular_impact * vec3(texture(specular_material.m_sampler, fragment_tex_coords));
            
    return (ambient + diffuse + specular);
}  

vec3 calc_point_light(PointLight pointlight, 
                      DiffuseMaterial diffuse_material,
                      SpecularMaterial specular_material,
                      SceneLight scenelight,                       
                      vec3 normalized_frag_model_normals, 
                      vec3 view_direction, 
                      vec2 fragment_tex_coords,
                      vec3 fragment_position){
    
    vec3 light_direction = normalize(pointlight.position - fragment_position);
    vec3 halfway_btwn_view_and_light_dir = normalize(light_direction + view_direction);
    
    // Ambient
    vec3 ambient  = scenelight.ambient * vec3(texture(diffuse_material.m_sampler, fragment_tex_coords));

    // Diffuse
    float diffuse_impact = max(dot(normalized_frag_model_normals, light_direction), 0.0);
    vec3 diffuse = scenelight.diffuse * diffuse_impact * vec3(texture(diffuse_material.m_sampler, fragment_tex_coords));

    // Specular
    float specular_impact = pow(max(dot(normalized_frag_model_normals, halfway_btwn_view_and_light_dir), 0.0), specular_material.m_shininess);
    vec3 specular = scenelight.specular * specular_impact * vec3(texture(specular_material.m_sampler, fragment_tex_coords));
    
    // Attenuation
    float distance_to_light = length(pointlight.position - fragment_position);
    float attenuation = 1.0 / (pointlight.constant + pointlight.linear * distance_to_light + pointlight.quadratic * (distance_to_light * distance_to_light));    
    
    ambient  *= attenuation;
    diffuse  *= attenuation;
    specular *= attenuation;

    return (ambient + diffuse + specular);
} 

\$\endgroup\$
0
\$\begingroup\$

This is solved! The light variables in the vertex shader were not being converted to tangent space (< vs <=). The fix is below:

    // Convert Pointlights to Tangent Space
    for(int i = 0; i <= active_pointlight_qty; i++){
        tangent_pointlights[i] = convert_pointlight_to_tangent_space(pointlight[i], tbn_matrix);
    }

    // Convert Directional Lights to Tangent Space
    for(int i = 0; i <= active_dirlight_qty; i++){
        tangent_dirlights[i] = convert_dirlight_to_tangent_space(dirlight[i], tbn_matrix);
    } 
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.