Author Topic: Exporting glTF 2.0 tangents?  (Read 2466 times)

When exporting to glTF 2.0, none of the glTF 2.0 viewers seem to correctly apply the normal-maps, reflections are wrong. It works reasonably well with little bumps, but large differences in the normals between low and high poly models don't reflect correctly at all in glTF (but seem to work fine in Unity, I haven't tested Unreal yet)

That might be because your exported glTF file does not contain TANGENT vertex data, so any glTF viewer will try to reconstruct the tangents, and these will be different from Substance Painter. It would be very helpful for the quickly growing glTF community if you could also export the tangents you generated in the glTF mesh.

As the developer of the open source Maya2glTF exporter, I tried to reconstruct the tangents using Blender's MikkTSpace code, but even then I can't get correct results. I'm also not sure if you guys are using that same code, and if so, what angular threshold you are passing. Would it be possible to share your code for generating the tangent-basis? Or to make a preset that specifically targets the glTF tangent bases, both the vertex-shader tangents and on-the-fly computed fragment shader tangents. It might well be that I'm not correctly using the MikkTSpace code, but I'm not sure what I'm doing wrong.

Thanks a lot,
Peter Verswyvelen


https://svn.blender.org/svnroot/bf-blender/trunk/blender/intern/mikktspace/mikktspace.h
https://github.com/KhronosGroup/glTF-WebGL-PBR

I agree that it would be good to offer the option to embed tangents in the exported gltf file.
That said, more explanations are due. The situation regarding tangent spaces in Painter is currently the following :
  • If your original mesh had tangents when importing it in Painter, Painter would use that tangent space.
  • If it did not, Painter recomputes the tangents using the MikkT code.

The differences you are observing may be because you imported in Painter a mesh with tangents which were not computed with MikkT in the first place.
Also, another thing worthy of note which may be causing the differences you are observing : making sure that you are using the exact same tangent space at each vertex (by either using the same code or by shipping the tangents with the mesh) is not sufficient for ensuring you will decode the normal maps in the same way in all software. You also need to apply the same code for interpolating the tangent spaces at each fragment within the triangles. Some software like UE4 choose to interpolate the normal and the tangent and recompute the binormal as a cross product of the other two at each fragment (multiplied by a sign to properly handle mirrored uvs). That's for example the case for the Unreal Engine 4. Some other software, like Unity, choose to interpolate the normal, tangent and binormal without further changes. Those are the two more common options but of course each software could possibly make a different choice (like renormalizing the vectors at each fragment, or even go as far as reorthogonalizing the tangent frame using the Gram-Schmidt process). Currently, Painter let's you choose between the "UE4" way or the "Unity" way of interpolating the tangents (the option is set in the project preferences). Eventually, we will probably do the same thing in Painter that we are currently doing in Designer and let the user be able to implement whatever algorithm they want to use both for computing the vertex tangent space and interpolating them in plugins with a common API.

Thanks a lot for this super fast reply!

Yes, we need to double check if glTF is interpolating the normals in the same way as Unity. At first sight this is the case, the normal and tangents are vertex attributes and the vertex shader computes the bi-tangent, taking the sign into account.

So you are saying that Substance Designer allows using a custom tangent-basis, per pixel? If so, that is insanely cool :)

For now we will try providing Substance Designer with custom tangents and bitangents through FBX, and see if that improves the results.

Thanks again!



I just made a silly mistake in my Maya2glTF exporter, I think I'm using the MikkTSpace code correctly now, although I would like to do some early welding with some small epsilon value. Are you guys welding the tangents too? Or just using the raw-output from MikkTSpace?

Thanks a lot for the  feedback.






I agree that it would be good to offer the option to embed tangents in the exported gltf file.
That said, more explanations are due. The situation regarding tangent spaces in Painter is currently the following :
  • If your original mesh had tangents when importing it in Painter, Painter would use that tangent space.
  • If it did not, Painter recomputes the tangents using the MikkT code.

The differences you are observing may be because you imported in Painter a mesh with tangents which were not computed with MikkT in the first place.
Also, another thing worthy of note which may be causing the differences you are observing : making sure that you are using the exact same tangent space at each vertex (by either using the same code or by shipping the tangents with the mesh) is not sufficient for ensuring you will decode the normal maps in the same way in all software. You also need to apply the same code for interpolating the tangent spaces at each fragment within the triangles. Some software like UE4 choose to interpolate the normal and the tangent and recompute the binormal as a cross product of the other two at each fragment (multiplied by a sign to properly handle mirrored uvs). That's for example the case for the Unreal Engine 4. Some other software, like Unity, choose to interpolate the normal, tangent and binormal without further changes. Those are the two more common options but of course each software could possibly make a different choice (like renormalizing the vectors at each fragment, or even go as far as reorthogonalizing the tangent frame using the Gram-Schmidt process). Currently, Painter let's you choose between the "UE4" way or the "Unity" way of interpolating the tangents (the option is set in the project preferences). Eventually, we will probably do the same thing in Painter that we are currently doing in Designer and let the user be able to implement whatever algorithm they want to use both for computing the vertex tangent space and interpolating them in plugins with a common API.

So I am understanding this correctly: When I import a mesh without tangents into SP, SP creates them according to MikkTSpace. When I export my model and textures as .gltf though, these tangents are stripped out again? I am not sure how this helps with anything. I think both three.js and babylon.js will make use of imported tangents, however will not recreate them themselves.. which leaves us MikkTSpace-tangent-less once more ;-)

Any updates on this? It's really unfortunate to still not have an option to export from SP to glTF including tangents.

Normal map baked in SP produces visible seams all over the place in glTF viewers if no MikkT tangents are present on the mesh. I'm forced to use Blender and export from there to have high-quality glTF content without obvious shortcomings. Would be awesome to publish from SP directly to glTF and USDZ, considering that the vast majority of the content gets textured in SP.