He estado tratando de implementar el mapeo normal usando OpenGL. Implementé la versión más básica, pero pasé a tratar de implementar el Mapeo Normal REAL que implica calcular Bi-Tangentes y Tangentes para cada vértice. Comencé implementando Shaders Fragment y Vertex como puedes ver a continuación:

Sombreador de vértices:

#version 330 core

in vec4 in_Position;
in vec2 in_Coordinates;
in vec3 in_Normal;
in vec3 tangent;
in vec3 bitangent;

out vec2 ex_textCoord;

out VS_OUT{
    vec3 FragPos;
    vec3 Normal;
    vec3 TangentLightPos;
    vec3 TangentViewPos;
    vec3 TangentFragPos;
} vs_out;

uniform mat4 ModelMatrix;
uniform vec4 VertColor;
uniform SharedMatrices
{
    mat4 ViewMatrix;
    mat4 ProjectionMatrix;
};

uniform vec4 plane;

uniform vec3 lightPos;
uniform vec3 viewPos;

void main(void)
{

    vec4 worldPosition = ModelMatrix * in_Position;
    gl_Position = ProjectionMatrix * ViewMatrix * worldPosition;
    vs_out.FragPos = vec3(ModelMatrix * in_Position);
    ex_textCoord = in_Coordinates;

    mat3 normalMatrix = transpose(inverse(mat3(ModelMatrix)));
    vs_out.Normal = normalMatrix * in_Normal;

    vec3 T = normalize(vec3(ModelMatrix * vec4(tangent, 0.0)));
    vec3 N = normalize(vec3(ModelMatrix * vec4(in_Normal, 0.0)));

    T = normalize(T - dot(T, N) * N);

    vec3 B = cross(T, N);

    mat3 TBN = transpose(mat3(T, B, N));

    vs_out.TangentLightPos = TBN * lightPos;
    vs_out.TangentViewPos = TBN * viewPos;
    vs_out.TangentFragPos = TBN * vec3(worldPosition);
    gl_ClipDistance[0] = dot(worldPosition, plane);

}

Fragmento Shader:

#version 330 core

out vec4 color;

in vec2 ex_textCoord;

in VS_OUT{
    vec3 FragPos;
    vec3 Normal;
    vec3 TangentLightPos;
    vec3 TangentViewPos;
    vec3 TangentFragPos;
} fs_in;

uniform sampler2D screenTexture; //Diffuse Texture
uniform sampler2D normalTexture; //Normal Mapping Texture

uniform bool normalMapping; //Enable or Disable Normal Mapping  

uniform vec3 lightPosition;
uniform vec3 lightColour;

void main()
{
    vec3 normal = texture(normalTexture, ex_textCoord).rgb;
    normal = normalize(normal * 2.0 - 1.0);

    vec3 Normalcolor = texture(screenTexture, ex_textCoord).rgb;

    //Ambient Light
    vec3 ambient = 0.1 * Normalcolor;

    //Diffuse Light
    vec3 lightDir = normalize(fs_in.TangentLightPos - fs_in.TangentFragPos);
    float diff = max(dot(lightDir, normal), 0.0);
    vec3 diffuse = diff * Normalcolor;

    //Specular Light
    vec3 viewDir = normalize(fs_in.TangentViewPos - fs_in.TangentFragPos);
    vec3 reflectDir = reflect(-lightDir, normal);
    vec3 halfwayDir = normalize(lightDir + viewDir);
    float spec = pow(max(dot(normal, halfwayDir), 0.0), 32.0);
    vec3 specular = vec3(0.2) * spec;

    color = vec4(ambient + diffuse + specular, 1.0f);
}

Ahora los sombreadores me parecen bien con toda honestidad, he estado viendo ejemplos de código y mis sombreadores parecen 1: 1 con ellos. Ahora bien, o el problema está en la iluminación (lo dudo un poco, pero es posible) o es en la forma en que calculo la Tangente y la Bi-Tangente que hago al cargar la malla como se puede ver a continuación:

Vec3 pos1, pos2, pos3, pos4, tangent1, bitangent1, edge1, edge2, normal;
    Vec2 uv1, uv2, uv3, uv4, deltaUV1, deltaUV2;

    for (int i = 0; i <= TempMeshRef->vertexIdx.size() - 3; i += 1) {

        pos1 = TempMeshRef->vertexData[TempMeshRef->vertexIdx[i]-1];
        pos2 = TempMeshRef->vertexData[TempMeshRef->vertexIdx[i+1]-1];
        pos3 = TempMeshRef->vertexData[TempMeshRef->vertexIdx[i+2]-1];
        //pos4 = TempMeshRef->vertexData[TempMeshRef->vertexIdx[i+3]-1];

        uv1 = TempMeshRef->texcoordData[TempMeshRef->texcoordIdx[i]-1];
        uv2 = TempMeshRef->texcoordData[TempMeshRef->texcoordIdx[i+1]-1];
        uv3 = TempMeshRef->texcoordData[TempMeshRef->texcoordIdx[i+2]-1];
        //uv4 = TempMeshRef->texcoordData[TempMeshRef->texcoordIdx[i+3]-1];

        normal = TempMeshRef->normalData[TempMeshRef->normalIdx[i]-1];

        //Triangle 1

        edge1 = pos2 - pos1;
        edge2 = pos3 - pos1;
        deltaUV1 = uv2 - uv1;
        deltaUV2 = uv3 - uv1;

        GLfloat f = 1.0f / (deltaUV1.x * deltaUV2.y - deltaUV2.x * deltaUV1.y);

        tangent1.x = f * (deltaUV2.y * edge1.x - deltaUV1.y * edge2.x);
        tangent1.y = f * (deltaUV2.y * edge1.y - deltaUV1.y * edge2.y);
        tangent1.z = f * (deltaUV2.y * edge1.z - deltaUV1.y * edge2.z);
        tangent1 = Normalized(tangent1);

        TempMeshRef->tangentData.push_back(tangent1);

        bitangent1.x = f * (-deltaUV2.x * edge1.x + deltaUV1.x * edge2.x);
        bitangent1.y = f * (-deltaUV2.x * edge1.y + deltaUV1.x * edge2.y);
        bitangent1.z = f * (-deltaUV2.x * edge1.z + deltaUV1.x * edge2.z);
        bitangent1 = Normalized(bitangent1);

        TempMeshRef->biTangentData.push_back(bitangent1);

Ahora les ordeno que observen los resultados que estoy obteniendo, son el siguiente error

Pmsmm
fuente