Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.

What is tangent.w? How to know whether it's 1 or -1? tangent.w VS unity_WorldTransformParams.w?

Discussion in 'General Graphics' started by bobozzz, Apr 27, 2017.

  1. bobozzz

    bobozzz

    Joined:
    May 27, 2015
    Posts:
    38
    Hi,

    I am so confused about what exactly is tangent.w and unity_WorldTransformParams.w.

    I am still a beginner and trying to figure out what is actually going on, after some searching:

    What I know:

    Tangents in Unity are represented as Vector4, with x,y,z components defining the vector, and w used to flip the binormal if needed. W stores handedness and should always be 1 or -1.

    unity_WorldTransformParams is for odd-negative scale transforms. W is usually 1.0, or -1.0. If an object has odd-negative scale transforms, it means it's mirrored. Binormal of mirrored object should be flipped.

    What I am confused:

    Does tangent.w come with model from Maya or 3ds max, or is calculated by Unity?

    If it comes with model, what does it indicate? If it's calculated by Unity, how is it calculated?

    If tangent.w stores handedness, and Unity is left hand, does it mean tangent.w will be -1 if I set graphics API to OpenGL (right hand) and will be 1 if graphics API is set to Direct3D?

    Some forum mentions tangent.w handles mirroring, then what is unity_WorldTransformParams used for? (Originally I thought tangent.w handles handedness and unity_WorldTransformParams handles mirroring.)

    Thanks!











     
    qsp18 likes this.
  2. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,266
    The model from an external application usually comes with normals, tangents, and binormals / bitangents (depending on which terminology you subscribe to). Unity throws away the actual binormal and encode the cross direction in the tanget's w component.

    You are also correct that for OpenGL and DirectX this value is inverted, but not exactly for the reason you're thinking. This comes down to what the tangent and binormal are representing; they are the direction of flow of the UVs. The tangent is the U of the UV, which for both OpenGL and DirectX is left to right (0.0 on the left, 1.0 on the right). The binormal is the V of the UV, which is different in OpenGL and DirectX. OpenGL is bottom to top, and DirectX is top to bottom. This is also where the difference in many engine's and 3d tools' preference for "+Y / -Y" normal maps comes from. Unity is +Y, which is the OpenGL standard, and Unreal is -Y, which is the DirectX standard. Obviously Unity is using DirectX on Windows, so most of the time the w component is going to be negative. However what if the texture UVs are inverted, not because the mesh scale is inverted, but because the mesh's UVs themselves are going the opposite direction life if the textures are mirrored, then it also needs the w inverted for the half that's mirrored.
     
    qsp18, dc1998, tinyant and 6 others like this.
  3. bobozzz

    bobozzz

    Joined:
    May 27, 2015
    Posts:
    38
    Thank you!

    About "Unity throws away the actual binormal and encode the cross direction in the tangent's w component.":

    Does it mean when we import model into Unity, on Windows machine (DirectX is used), tangent.w will be -1, and on macOS (OpenGL is used), tangent.w will be 1?

    About mirroring:

    If the mesh's U of UV is going to the opposite direction (mesh has negative scale on the X direction), tangent is inverted. That means cross product binormal should be flipped too. In this situation, unity_WorldTransformParams.w will be -1.

    If the mesh's V of UV is going to the opposite direction (mesh has negative scale on the Z direction), binormal should be flipped and unity_WorldTransformParams.w will also be -1.

    Other than that, unity_WorldTransformParams.w will be +1.

    Am I understanding this correctly?
     
  4. bobozzz

    bobozzz

    Joined:
    May 27, 2015
    Posts:
    38
    I guess what I am saying here is wrong? It should be tangent.w who is handling this, instead of unity_WorldTransformParams.w?

    Then what is unity_WorldTransformParams.w used for?
     
  5. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,266
    No, as best I can tell, the on disk mesh data is stored as if it's for OpenGL, regardless of what the final platform is. The tangent.w or the unity_WorldTransformParams.w is then flipped depending on the platform, not sure which to be honest.

    The unity_WorldTransformParams.w is a constant value of +1.0 for an entire mesh, it flips to -1.0 for the entire mesh if it is scaled so that an odd number of scale components are negative (like your example of a negative scale on X). The mesh doesn't need to be scaled for the UVs to be going in the opposite direction, which is why that flip is stored in the tangent's w component, the mapping of the UVs is completely arbitrary and up to the content creator.

    For example this is a single mesh with no scaling (1,1,1).
    mirrored UVs.png
    Top right has a tangent.w of -1.0, as does the bottom left, where as the top left and bottom right are +1.0. However the unity_WorldTransformParams.w is +1.0 for everything.
     
  6. bobozzz

    bobozzz

    Joined:
    May 27, 2015
    Posts:
    38
    Now I understand! Thank you so much!!
     
  7. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,266
    Now that you're no longer confused. An extra bit to throw your brain under the bus ... Unity doesn't flip the texture coordinates on the mesh when rendering in OpenGL vs DirectX, it flips the textures when they're uploaded to the GPU!
     
    KingOfShit, dc1998, npatch and 2 others like this.
  8. bobozzz

    bobozzz

    Joined:
    May 27, 2015
    Posts:
    38
    Does it mean in this line of code:

    half3 normalTangent = UnpackScaleNormal(tex2D(_NormalMap, texcoords.xy), _NormalScale);

    NormalMap is flipped upside down on DirectX platform?

    And tangent.w is only used for flipping vertex normal and the texture flipping you mentioned is for normal map flipping?
     
  9. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,266
    Not just normal maps, all textures, but it has the side effect of solving the issue of UV and binormal differences between platforms.
     
    dc1998, npatch and bobozzz like this.
  10. bobozzz

    bobozzz

    Joined:
    May 27, 2015
    Posts:
    38
    One more question:)

    How does Unity know which uv is flipped and which is not? Is the mirroring property of UVs originally stored in the tangent.w?
     
  11. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,266
    To a degree it depends on how your mesh was exported, and your import settings, but the basic answer is it knows from the normals, tangents and binormals in the mesh it's importing. The longer, and perhaps simpler answer, is it knows the same way you know when you look at the above image, but looking at the direction the texture (or more specifically the UVs) is going. There's an expected handedness to the UV "flow", and if it doesn't match that orientation then it's mirrored on one axis or the other, and which axis doesn't actually matter.
     
    dc1998, npatch, brokenm and 1 other person like this.
  12. bobozzz

    bobozzz

    Joined:
    May 27, 2015
    Posts:
    38
    Thank you! bgolus!!
     
  13. doubleqangel

    doubleqangel

    Joined:
    Dec 20, 2017
    Posts:
    1
    How does unity handle the tangent.w when using static batch? I find that the binormal is wrong in a odd-negative scale object. I use unity 2018
     
  14. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,266
    I believe the fix for this is to stop using Unity 2018 because I think this bug got fixed in 2019.