"Tangents and Binormals, Tangent Space, Tangent Space per Fragment"
Hey folks - curious if anyone could offer up some explanations of what those things exactly are, how they might be related, and how they should be considered in one's workflow etc.
I'm pretty up to speed on normal baking etc. I understand the idea of a synced baking workflow, etc.
I've recently switched to baking in Painter from years of dear sweet Xnormal, so I'm trying to get my process dialed in.
When I am exporting .FBX from Maya, I have the option of exporting the "Tangents and Binormals" with the FBX. What exactly are the Tangents and Binormals? And is the "Tangents" the same as a "Tangent Space" that one would bake in? Or is there some difference, and maybe they are related and work together - As in - Mikkt tangent space is the math used to compute the tangents on the exported FBX model? Or, are the tangents being exported with FBX the actual tangent space itself, that would in turn override the default tangent space in whatever the baking app is?
That make sense?
Also, in Painter, it has an option to "Compute tangent space per fragment". What does that mean? How is that related to the Tangents being exported with the FBX, and the Tangent Space (Mikkt) being used for baking or display?
So yeah, if anybody could provide me with some info or links or whatever, that would be super cool and most appreciated. (Or any other info that you think might be helpful or relevant to figuring this all out and dialing in my process.)
Thanks.
-Trevor
Replies
When you export tangents and binormals to your FBX from Maya, you are including those vectors as Maya computed them so that your renderer can use the same vectors. But, since you're baking in Substance Painter and (I assume) going to UE4 or Unity which both support MikkTSpace variants, there's usually no need for the Maya tangents since the baker and the renderer both know how to compute the same tangent space given the same object and UVs. If you're freelancing, you should ask your client whether you should bake in Maya tangent space or MikkTSpace and export tangents accordingly. (I'm assuming here that Substance Painter can use the exported tangents and binormals if you exported them from Maya. If it can't, then you would need to bake normal maps in Maya and export the tangents and binormals to your renderer if you needed to bake maps in Maya tangent space. I haven't baked with Substance Painter so I'm not confident one way or the other.)
Some renderers pass all three vectors to the GPU as per-vertex data, or vertex attributes. Cryengine and Unity do this. However, some other renderers pass just the normal and the tangent vectors to the GPU as per-vertex data, and then in the pixel shader they use the interpolated value of the normal and tangent vectors to compute the bitangent. The bitangent is just the cross product, or maybe the opposite of the cross product, of these two vectors in this case. Doing this saves a bit of memory and vertex processing time, but costs a bit more processing time in the pixel shader, so it's less useful for weak GPUs and more useful if there are a lot of vertices. Doing things this way also yields (in most cases) subtle differences in the way that the normal map looks. So to get a correct result, you have to make sure that the baker is informed of which way the renderer is getting the bitangent vector. Again, Unity and Cryengine (and, as it happens, xNormal's 3D preview) pass the bitangent as vertex data so it's interpolated as such, and almost every other renderer that I know of computes the bitangent in the pixel shader. So if you're using Unity, you should tell Substance Painter to not compute tangent space per fragment, and if you're using UE4, you should tell Substance Painter to compute tangent space per fragment.
To clarify - The "Tangent" is vertex data, and the "Tangent Space" is the specific math used to calculate the geometry's tangent, correct? For example, using Mikkt to calculate the tangents on a model?
FYI - I forgot to mention, we are on a proprietary engine, so I'll have to find out the above specifics on binormal/bittangent calculations.
Also, we are not using a synced workflow, but our engine and Maya do match pretty close. Less than ideal, I know, but it's beyond my control.
If you're using a proprietary engine, there are two good ways to get a synced tangent space working if your testing has shown some discrepancies. You could integrate MikkTSpace, which is open source with an extremely permissive license that allows its source code to be integrated with proprietary projects. See here: https://github.com/dfelinto/blender/tree/master/intern/mikktspace and here: http://gamedev.stackexchange.com/questions/128023/how-does-mikktspace-work-for-calculating-the-tangent-space-during-normal-mapping for more information on how to do this. Depending on how fucked your code is (if it's less fucked than Cryengine you should be able to do it without too much fuss) this should be pretty easy to do because of the clean, simple design of the MikkTSpace API. Just make sure you understand whether your engine calculates bitangents in the pixel shader, or uploads them in a vertex attribute. MikkTSpace bakers can handle either case.
The other easy way that you could do it is to export the tangents and binormals with your FBX file and have the engine read them in and upload them to the GPU as-is. If memory serves, Maya bakes normal maps assuming that your engine calculates bitangents in the pixel shader, but I'm not sure about this so you would have to test it. I haven't implemented this way of doing things myself.
The third way to do it, which I wouldn't recommend because it's more difficult than the other two ways, would be to look for documentation on how Maya's tangent space works and check your code to make sure it's exactly the same.
The fourth way to do it would be to write an engine utility that imports world-space normal maps and uses the tangent basis that your engine calculates to convert them to tangent space. This is what I would recommend if every other technique has been investigated and deemed unworkable.
I would personally strongly recommend option 1 because if your company hires some freelance artists they can bake normal maps using any baker that can output MikkTSpace normal maps, which includes xNormal, Substance, Toolbag 3 I assume, Handplane Baker, Mightybake, Modo, and Blender at least, and probably a couple of others. If you use option 2 they'll have to bake normal maps in Maya, Mightybake, or Handplane Baker, or be sure to use a baker that reads tangents from .fbx files, which all are good options but easier to mess up.
Before you do any of these things, you should do a tangent space test to make sure that your renderer isn't already synced to something. For this purpose I favor a completely smooth-edged 6-face cube with one UV island, with a beveled cube baked down to a normal map for it. This setup is a worst case in which most renderers that are correctly synced should be expected to still behave correctly. If the faces of the cube appear completely flat and smooth in-engine (with perhaps some tiny bumps from compression or bit-depth artifacts) then your tangent space should be synced. By default, you need to export your tangents and binormals to Substance Painter for it to use Maya's tangent space for baking, so given that you said your renderer is kind of like Maya's tangent space I would recommend exporting tangents and binormals with your lowpoly model. If your engine were synced to MikkTSpace you would want to avoid exporting tangents and binormals with your lowpoly model so that Substance Painter calculates a MikkTSpace-compatible tangent space for your lowpoly model. It's the same way that xNormal did it: if you exported tangents, it uses them, and if you didn't export tangents, it calculates them.
So, if I export tangents into Substance from Maya, via FBX, I will be baking in Maya's native tangent space, instead of Mikkt?
I thought that if I exported from Maya FBX with Tangents and Binormals, into Painter, and baked - I would still be baking in Mikkt Tangent Space. It would just be with the Tangents on the verts from Maya, instead of the Tangents Mikkt came up with.
So a cube with all soft edges, baked in Painter, with Tangents exported from Maya, would look perfect in our (theoretical) Maya tangent space based engine?
In which case, if our engine was truly synced to Maya tangent space, it would be a synced workflow? Baking in Painter with exported Tangents?
I was under the impression "Tangents" and "Tangent Space" were two different, but related things. "Tangent Space" was the algorithm to compute the normal map, based off of the Tangents, Binormals etc of the geometry.
Thanks again Jed.
-Trevor
I export the texture set and set up the material using it in Toolbag 2, which is synced with Maya if you set the imported mesh to use Maya's tangent space. (I could also view it back in Maya's viewport.) This is what it looks like:
Obviously this isn't flat. This is what an unsynced tangent space looks like. Trying again with Substance Painter NOT computing tangent space per-fragment, here's the result I get:
This obviously isn't synced to Maya tangent space either, and neither is it synced to MikkTSpace (switching the mesh to xNormal/Mikk in Toolbag verifies this. You can get Mikkt-synced normal maps for Toolbag 2 from SP2 but you have to check the box for interpolation in the pixel shader.) Which of these two is better is really a matter of taste. Neither is correct, and neither is "synced" to anything in particular. Finally, a normal map that I've baked in Maya with Transfer Maps (you'd want to use Turtle and get a 16-bit output of some kind instead for a production workflow, probably):
This is what it should look like. So, I wasn't able to get something synced from SP2 for some reason. It would be a miracle if you could get something synced to your proprietary engine from SP2, in my opinion. You could bake object-space normals in SP2 and convert them in Handplane and that would be correctly synced to Maya's tangent space, but perhaps not to your proprietary engine.
After some further fiddling around, even my Maya-baked normal map has ended up unsynced in the Maya viewport somehow. I am unsure what went wrong and perhaps I'll try again tomorrow when I'm more awake and less drunk.
"Tangent" is one of three vectors that make up the tangent basis. "Tangent basis" means that you can add those three vectors each multiplied by a number supplied in your normal map and get a vector in world space. "Tangent space" refers to a particular group of these bases that varies in a defined, predictable way across the entire mesh, and tangent spaces must be defined with the same values at all places on the mesh's faces in the baker and the renderer for the result to be correct. When SP2 imports tangents and binormals for baking, that only guarantees that the tangent space is the same at vertices, and everywhere else it will be slightly incorrect because somehow the tangents are interpolated differently between vertices.