Search Unity

  1. Good news ✨ We have more Unite Now videos available for you to watch on-demand! Come check them out and ask our experts any questions!
    Dismiss Notice

Question about the Toksvig factor

Discussion in 'Shaders' started by MaT227, Dec 18, 2015.

  1. MaT227

    MaT227

    Joined:
    Jul 3, 2012
    Posts:
    627
    Hi there,

    I am trying to calculate the Toksvig factor of my normal maps to use it as a gloss map but I am facing some difficulties in my surface shader because it seems that some things are done behind the hood.
    Another thing is that if I use a normal map texture type, the result is quite false compared to a normal texture type import option.

    Has anybody achieved to implement the Toksvig factor on a surface shader ?
    Thanks a lot
     
  2. Farfarer

    Farfarer

    Joined:
    Aug 17, 2010
    Posts:
    2,249
    You'll need to unpack the normal map first, as the stored normal map is missing the blue channel and the red channel is stored in the alpha channel. To have it work, you need to unswizzle then uncompress the range of the normal map.

    The UnpackNormal macro will help with that.

    Other than that, it should work fine. I've not done it in a surface shader, but I've managed it in OpenGL without any fuss.
     
  3. MaT227

    MaT227

    Joined:
    Jul 3, 2012
    Posts:
    627
    Thank you for your answer @Farfarer,

    I am trying to use the example from here : http://selfshadow.com/sandbox/gloss.html
    But I can't achieve the same result as the one illustrated by the Toksvig AA. The fact is that is I use the UnpackNormal or UnpackScaleNormal I can't get the length of the normal, I have to do it manually.

    Here is a sample code that is quite close to the result of selfshadow but this is not the same. What am I doing wrong ?

    Code (CSharp):
    1. // UnpackScaleNormal and UnpackNormal gives bad result.
    2. float normalMapLen = length(tex2D(_BumpDetailMap, IN.uv_BumpDetailMap) * 2 - 1);
    3. normalMapLen = 1.0 / saturate(normalMapLen);
    4. float result = 1.0 / (1.0 + _Power * (normalMapLen - 1.0));
    5. // Output in the Albedo to see the result, no lighting is applied, just Albedo.
    6. o.Albedo = result;
     
  4. Farfarer

    Farfarer

    Joined:
    Aug 17, 2010
    Posts:
    2,249
    Right, my bad. I thought you meant generating the factor; http://www.selfshadow.com/sandbox/toksvig.html

    So using it this way won't work because it's stored as a normal map, swizzled.

    Unity unpacks this normal map to a normal whose length is always 1.0.

    The proper length of the normal is 1.0, that's the sole reason you can unpack it in the first place (it should be a normalized vector, so it's always of unit length).

    UnpackNormal uses that to it's advantage. Two of the components (the X and Y) of the vector are stored in the texture. The third one (Z) can be worked out because the length of the vector is 1.0 (which means that it's 1.0 - sqrt(x*x + y*y)). You know it's always positive value because a negative Z component would make the normal would point inwards from the surface.

    In this case, it means that as the vector you're getting doesn't have any length variance in it, all you're doing there is calculating 1.0 in a really roundabout fashion :p

    To get around that, you'll have to store it as a regular texture (not set it's type to Normal) and unpack it the simple way (normal.xyz*2-1).

    As for your code, you're including the length of the alpha channel in there. The normal map likely doesn't have one so it's defaulting to 1.0, which will throw off the length calculation.

    Make sure you specify just the xyz of the texture, that should give it better results!
    Code (csharp):
    1. float normalMapLen =length(tex2D(_BumpDetailMap, IN.uv_BumpDetailMap).xyz * 2.0 - 1.0);
     
  5. MaT227

    MaT227

    Joined:
    Jul 3, 2012
    Posts:
    627
    Thanks a lot for your explanations @Farfarer, this makes sens now :)

    I have some last questions about the normals. If I want to use a scale factor and Unpack them using the Unpack Unity functions should I normalize after sampling them with tex2D and then use Unpack function ?

    Why if I use the fadout mip maps option of the texture import panel the result is all broken ?
     
  6. Farfarer

    Farfarer

    Joined:
    Aug 17, 2010
    Posts:
    2,249
    With the scale factor, you'll probably want to unpack the normal (*2-1), get the Toksvig factor, then scale the normal (to scale the normal, multiply the normal.xy by the scale factor, then normalize it).

    Then you can probably scale the Toksvig factor by the same amount to compensate (although it might be
    Code (csharp):
    1. toksvig = lerp(toksvig, 1.0, scaleFactor);
    as white is the "less noisy" toksvig...).


    The fadeout mips will be altering each mip level (I suspect it's blending to a specific or average colour, not sure as I've not played with those options before) which will change the results.

    Each mip level of your normal map isn't renormalized when it's generated, meaning the length of the normal for the mip isn't always 1.0 - the mip is just the average of the nearby pixels at half the resolution (like downsizing an image in Photoshop).

    When the normal map is sampled, it's blending between those mips based on the distance and angle of the surface. The "rougher" the normal map is in the top mip, the more different the length of the vector is in each lower mip due to averaging many different values together. The Toksvig factor is effectively just that - the difference between the true unit length of the top mip and the sampled length.

    With the fadeout mip options, there will be some extra things happening in the lower mips which will alter their vector length and throw off your Toksvig factor.
     
  7. MaT227

    MaT227

    Joined:
    Jul 3, 2012
    Posts:
    627
    Right !

    Thank you for your time and your great explanations as always !
     
  8. n00body

    n00body

    Joined:
    Dec 17, 2010
    Posts:
    691
  9. MaT227

    MaT227

    Joined:
    Jul 3, 2012
    Posts:
    627
    @n00body,
    Thank you for your advice. After testing it, I must admit that the result is not what I expected because I am not using a classic Blinn Phong, I'll take a look at the work of DICE and Ready at Dawn.

    Thank you again ;)
     
unityunity