Parsing tangent values correctly | c++/opengl

Started by
14 comments, last by Eric Lengyel 7 years ago

Ive been trying to make a 3Dmodel parser, on one hand to understand the process better, and on the other hand to be able to make formats that I can call my own, but the result creates seams once I introduce normal mapping. Maybe somebody can explain what is happening, and/or what I should be doing different.

What I do is make an object in maya (in this a case a cube-sphere), export as obj and then try to parse it. My problem is: how do I handle shared vertices and edges for tangents? When it comes to vertex_normals this is fairly straight forward:


    vector <vec3>normalref(normalsize, vec3(0)); //normalsize, amount of vn, fill with 0

    //fill normalref with calculated normals
    vec3 normalbuffer;

    //i=vert1, i+1=uv1, i+2 vn1
    //i+3=vert2,i+4=uv2,i+5=vn2
    //i+6=vert3, i+7=uv3, i+8=vn3
    for (size_t i = 0; i < totalrefs.size(); i += 9) {
        normalbuffer = cross(
            vref[totalrefs[i + 3] - 1] - vref[totalrefs[i] - 1],
            vref[totalrefs[i + 6] - 1] - vref[totalrefs[i] - 1]);

        normalref[totalrefs[i + 2] - 1] += normalbuffer;
        normalref[totalrefs[i + 5] - 1] += normalbuffer;
        normalref[totalrefs[i + 8] - 1] += normalbuffer;
    }
    for (auto&x : normalref)x = normalize(x); //and normalize

For each face, add the cross (plane angle) to each vn connected, then after, normalize each of the vns, And you will have a vertex_normal that will work with a seamless phong shader.

But when It comes to tangent values, this is not as straight forward. The idea is that you convert the tangent on gpu, alongside with the normal for that vertice/corner, and make a bitangent, and tbn matrix, that you use for further calculations. But what I cant figure out is: How do you balance the tangent values for each side?

I keep getting edges that overlap and shadows that do not make any sense. Calculating the tangents themselves for each face is not very hard:


for (size_t i = 0; i < totalrefs.size(); i += 9)
    {
        edge1 = vref[totalrefs[i + 3] - 1] - vref[totalrefs[i] - 1];
        edge2 = vref[totalrefs[i + 6] - 1] - vref[totalrefs[i] - 1];
        deltaUV1 = uvref[totalrefs[i + 4] - 1] - uvref[totalrefs[i + 1] - 1];
        deltaUV2 = uvref[totalrefs[i + 7] - 1] - uvref[totalrefs[i + 1] - 1];
        f = 1.0f / (deltaUV1.x * deltaUV2.y - deltaUV2.x * deltaUV1.y);

        tangentbuf = normalize(f*vec3(
            (deltaUV2.y * edge1.x - deltaUV1.y * edge2.x),
            (deltaUV2.y * edge1.y - deltaUV1.y * edge2.y),
            (deltaUV2.y * edge1.z - deltaUV1.y * edge2.z)));

        tangents[tangcount++] = tangentbuf;
        tangents[tangcount++] = tangentbuf;
        tangents[tangcount++] = tangentbuf;
    }

But this approach that works with vertex_normals, does not work for tangents. Even if i map them per vertex, per uv, or per vn. I get the same poor result showing seams. As far as I can gather, the problem is shared vertex/corner balancing, and I do not know how to do that correctly.

Somebody help!

this is what it currently looks like:

RlnQ0FB.png

Where the specular value is turned up, to make out the seam more clearly. This seam is not there when I use normals to do the shading, and, each face isnt square-ish either, but interpolated properly. Im pretty certain this is caused by the way I either calculate the tangents, or how I index them, can somebody explain to me how this should be done?

Advertisement

Or maybe someone can just suggest a way to parse the tangents? Assuming you have a working way to get vertices, uvs and normals into the environment?

Just to be sure that your problem is really related to the TBN coordinates. You don't have seams with applying texturing ?

Also, seams with TBN is something that can happen.

Just to be sure that your problem is really related to the TBN coordinates. You don't have seams with applying texturing ?

Also, seams with TBN is something that can happen.

The texturing does not get seams, and when I make use of only the normal for non-normal-mapping (plain phong/ads shading) I do not get seams either.

Tangent calculation seems to get messed up when sharing edges/vertices and when wrapping around

vqFeKaK.png

OK. Try to render your TBN unit vectors now and see if things look OK at the area where you have seams.

OK. Try to render your TBN unit vectors now and see if things look OK at the area where you have seams.

Oh they are normalized already


for (auto&x : tangentref)x = normalize(x); //clean up

OK. Try to render your TBN unit vectors now and see if things look OK at the area where you have seams.

Oh they are normalized already


for (auto&x : tangentref)x = normalize(x); //clean up

I wanted to check if some of the TBN vectors could be reversed/swapped.

From your first image it looks like you have a little decay. This can come from the original topology or from something else.

Just display in the screen each of the TBN vectors with a distinct color and look at the region where you have these seams. I suspect this is the area where the texture goes from the right to the left again.

Also, check with another model (not spherical), and check if you have such seams at this area (junction of texture coordinates when they move from 1 to 0 again).

Just display in the screen each of the TBN vectors with a distinct color and look at the region where you have these seams. I suspect this is the area where the texture goes from the right to the left again

What are possible fixes for that? Im using the wrong matrix or something? I've been trying to recalculate the tangents, but maybe I shouldnt?

export as obj and then try to parse it

Don't use obj as your interchange format; use a format that supports tangents.
Don't compute your own normals/tangents from the vertex positions either -- use the exact values that were exported into your file.

This topic is closed to new replies.

Advertisement