FBX Static Mesh incorrect blending of tangents.

Unreal is currently blending tangents incorrectly for static meshes. This breaks normal maps that are baked to sync with MikkTSpace, causing ugly seams across the meshes.

Here’s a very simple file showing the issue; 3 tris joined together with 1 of the edges (highlighted in the image) having a UV split. All 3 faces share a single smoothing group.

  • The two vertices at the sides are correctly blended as they share normals, positions and UV coordinates.

  • The split at the bottom vertex is correct (it’s on a UV seam).

  • The central vertex shares normal, position and UV coordinates, but you can see it has 3 separate tangent vectors. This is incorrect. It should only have 1; a blended tangent from all 3 polygons.

[You can download the FBX for the mesh shown in the image here.][1]

What you’re seeing is the correct intended results.

On the single edge in the center of the picture you can see that there is a single normal along the split edge the in UV. The Tangents also line up with what is expected. There are three on that top point. If we look at the the UV to understand why this is we can see that there are three points that correlate with this as well. The Bottom right and left point and the middle point in the UV space adding up to the three tangents.

Taking that into account we can then look at the vertex count we have which is 7. If we add up the tangents we can see there are a total of 7.

Thanks!

Tim

The vertex count displayed changes as you blend the tangents - if done correctly it reads 5 vertices rather than 7.

That central vertex should have 1 tangent vector. Because it should take the face-tangents of all 3 of the triangles it shares and add them together, then normalize them. Then orthonormalised, etc.

The bottom left and right points in the UV space are not related to that central vertex - they are related to the vertex at the bottom (the one that shows 2 tangents, correctly).

If you rig this mesh to a bone and import it as a skeletal mesh, it will display 5 vertices and blend the tangents correctly. The issue shown here with static meshes is not correct or expected behaviour.

I have already fixed this in your source code for this in my local fork of the engine, I’ll test it some more and send a pull request so you can get it into the proper build and then this can be answered.

Would you mind posting a link here to your pull request once you will have done it ? I subscribed to this question to stay up to date as I am as well interested in this matter. :slight_smile:

Sure, if you want to play with it yourself (and this is off the top of my head, sorry if it’s kinda vague);
You need to look for the ComputeTangent method in MeshUtilities.cpp.
Where it says it’s comparing just the positions, and the smoothing will be compared later, add in a check for UV comparison.

Then later, when it’s defining NewFanFace (I think it’s called? Set bBlendTangents to true. (It’s somehwere that it’s defining bFilled = (OtherFace == ThisFace) and then bBlendTangents and bBlendNormals to be the same as bFilled… should be fairly obvious.)

I’ve not tested it with many meshes, though, all I know so far is that it will now blend the tangents it’s supposed to blend and not the ones it shouldn’t blend when you’ve got a fully smoothed mesh.

I’ll add in a normal comparison, too, so it doesn’t blend tangents across normal splits.

There does seem to be a few strange shading splits remaining where the tangents get split, however. Not yet sure if this is an issue with the normal map, the shader or my code modifications.

Tempted to just rewrite the whole ■■■■ function, it seems a bit of a mess.

And now you’ve accepted your reply as the answer on my behalf, Tim, I’m unable to deselect your reply as being the answer.

This is not resolved. Can you untick it?

The OP has submitted a pull request for this, but it has not been accepted or implemented into the engine. This is marked as resolved until this point for our tracking purposes.

@Farfarer: If your pull request is accepted feel free to post here and I will update accordingly.

Hey Fabrice,

JedTheKrampus has beaten me to it and got the reference implementation of MikkTSpace into UE4. His pull request is over here if you want to give it a go locally; https://github.com/EpicGames/UnrealEngine/pull/561

I’ve been testing it and it works fine - although you’ll still need to bake normal maps from xNormal with +X-Y+Z, as before.

Thanks a lot ! :slight_smile:

So the full pull request is up, which fixes MikkTSpace for both static and skeletal meshes. Spencer (JedTheKrampus) and I have tested it with a bunch of meshes and it seems pretty solid.

If this could be tested by the folks at Epic and implemented into the next release, it should help out artists everywhere with a fully synced normal mapping pipeline. Not to mention proper support for mirrored normal maps and improved vertex counts.

Also, if you’re running a local fork, could you also test this and let us know if you find any edge cases where things are going wrong? We’ve not found any yet, but more eyes on it will make certain. Thanks!

Here’s the pull request URL, please give it a look over :slight_smile:

Hallo pleas help me i have exported the mash from 3dmax 2018 to unreal enguine 4. UV is made everything is ok when i am doing render in UE4 have this problem ia do not know if it is the shadow or material… pleas help