thepalacsinta007
thepalacsinta007

Reputation: 33

Normal mapping bug

Im working on a 3D OpenGL engine with the LWJGL. I managed to do the model importing part with Assimp, now working on the normal mapping. Luckily Assimp can calculate tangent space for me, but it isn't working correctly. Here is a picture how is it working on the sponza model:

Original

This is the T visualized from TBN matrix:

Tangents

The code looks like this in the vertex shader:

mat3 normalMatrix = transpose(inverse(mat3(transformationMatrix)));
vec3 T = normalize(normalMatrix * tangent);
vec3 N = normalize(normalMatrix * normal);
T = normalize(T - dot(T, N) * N);
vec3 B = normalize(normalMatrix * bitangent);

if (dot(cross(N, T), B) < 0.0){
        T = T * -1.0;
}
TBN = transpose(mat3(T, B, N));

Its checking if the model has symetric UVs, and fixes it. I think this causes the problem, because the B from TBN looks even worse.

Bitangents from Assimp

After weeks i tried to calculate tangents and bitangent by myself, but my bitangents are looking worse than Assimps:

own Bitangents

private void generateTangentBitangent(){
    for(int i = 0; i < indices.size(); i+=3){
        Vector3f v0 = new Vector3f (vertices.get(indices.get(i)).getPos());
        Vector3f v1 = new Vector3f (vertices.get(indices.get(i+1)).getPos());
        Vector3f v2 = new Vector3f (vertices.get(indices.get(i+2)).getPos());

        Vector2f uv0 = new Vector2f (vertices.get(indices.get(i)).getTextureCoord());
        Vector2f uv1 = new Vector2f (vertices.get(indices.get(i+1)).getTextureCoord());
        Vector2f uv2 = new Vector2f (vertices.get(indices.get(i+2)).getTextureCoord());

        Vector3f e1 = new Vector3f (v1.sub(v0));
        Vector3f e2 = new Vector3f (v2.sub(v0));

        Vector2f deltaUV1 = new Vector2f (uv1.sub(uv0));
        Vector2f deltaUV2 = new Vector2f (uv2.sub(uv0));

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

        Vector3f tangent = new Vector3f ((e1.mul(deltaUV2.y()).sub(e2.mul(deltaUV1.y()))).mul(r));
        //System.out.println(tangent);
        Vector3f bitangent = new Vector3f ((e2.mul(deltaUV1.x()).sub(e1.mul(deltaUV2.x()))).mul(r));

        if(vertices.get(indices.get(i)).getTangent() == null)
            vertices.get(indices.get(i)).setTangent(new Vector3f(0,0,0));
        if(vertices.get(indices.get(i)).getBitangent() == null)
            vertices.get(indices.get(i)).setBitangent(new Vector3f(0,0,0));
        if(vertices.get(indices.get(i+1)).getTangent() == null)
            vertices.get(indices.get(i+1)).setTangent(new Vector3f(0,0,0));
        if(vertices.get(indices.get(i+1)).getBitangent() == null)
            vertices.get(indices.get(i+1)).setBitangent(new Vector3f(0,0,0));
        if(vertices.get(indices.get(i+2)).getTangent() == null)
            vertices.get(indices.get(i+2)).setTangent(new Vector3f(0,0,0));
        if(vertices.get(indices.get(i+2)).getBitangent() == null)
            vertices.get(indices.get(i+2)).setBitangent(new Vector3f(0,0,0));

        vertices.get(indices.get(i)).getTangent().add(tangent);
        vertices.get(indices.get(i)).getBitangent().add(bitangent);
        vertices.get(indices.get(i+1)).getTangent().add(tangent);
        vertices.get(indices.get(i+1)).getBitangent().add(bitangent);
        vertices.get(indices.get(i+2)).getTangent().add(tangent);
        vertices.get(indices.get(i+2)).getBitangent().add(bitangent);
    }

    for (int i = 0 ; i < vertices.size() ; i++) {
        vertices.get(i).getTangent().normalize();
        vertices.get(i).getBitangent().normalize();
    } 
}

Can someone help me please what causes the problem ?

Upvotes: 1

Views: 845

Answers (1)

j00hi
j00hi

Reputation: 5941

In which space are the tangents/bitangents/normals which you present on your images? Judging from your code sample, they are probably expected to be in tangent space.

However, getting the tangent space vectors can be achieved easier. You don't have to Transform tangent, normal, and bitangent with normalMatrix, but instead just use the axes in object space:

vec3 normalOS    = normalize(normal);
vec3 tangentOS   = normalize(tangent);
vec3 bitangentOS = normalize(bitangent) // or calculate via cross(normalOS, tangentOS);
mat3 TStoOS      = mat3(tangentOS, bitangentOS, normalOS); // transform from tangent space into object space
mat3 OStoTS      = transpose(matrixTStoOS); // The transpose of an orthogonal matrix is it's inverse matrix

If you need the matrix, which transforms from tangent space into world space, you would calculate it like follows:

vec3 normalWS    = normalize(normalMatrix * normal);
vec3 tangentWS   = normalize(normalMatrix * tangent);
vec3 bitangentWS = normalize(cross(normalWS, tangentWS))
mat3 TStoWS      = mat3(tangentWS, bitangentWS, normalWS); // transform from tangent space into world space
mat3 WStoTS      = transpose(matrixTStoWS); // transform from world space into tangent space

Upvotes: 0

Related Questions