Skip to content

Instantly share code, notes, and snippets.

@tkokof
Created October 29, 2018 08:56
Show Gist options
  • Save tkokof/b05a8e794a5200abbba9ff13e1b4f98d to your computer and use it in GitHub Desktop.
Save tkokof/b05a8e794a5200abbba9ff13e1b4f98d to your computer and use it in GitHub Desktop.

Revisions

  1. tkokof created this gist Oct 29, 2018.
    77 changes: 77 additions & 0 deletions NormalCompression.cs
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,77 @@
    public static class Sample
    {
    static int gsN = 127; // N(N+1)/2 = 8128 < 2^{13}
    static float gsB = 2 * gsN + 1;
    static float gsB2 = gsB * gsB;
    static float gsFactor = (gsN - 1) * Mathf.Sqrt(0.5f);
    static float gsInvFactor = 1.0f / gsFactor;

    public static ushort CompressNormal(Vector3 normal)
    {
    var x = normal.x;
    var y = normal.y;
    var z = normal.z;
    Debug.Assert(MathUtil.IsSame(x * x + y * y + z * z, 1));

    // Determine octant.
    ushort index = 0;

    if (x < 0.0)
    {
    index |= 0x8000;
    x = -x;
    }
    if (y < 0.0)
    {
    index |= 0x4000;
    y = -y;
    }
    if (z < 0.0)
    {
    index |= 0x2000;
    z = -z;
    }

    // Determine mantissa.
    ushort usX = (ushort)Mathf.Floor(gsFactor * x);
    ushort usY = (ushort)Mathf.Floor(gsFactor * y);
    ushort mantissa = (ushort)(usX + ((usY * (255 - usY)) >> 1));
    index |= mantissa;

    return index;
    }

    public static Vector3 DecompressNormal(ushort index)
    {
    ushort mantissa = (ushort)(index & 0x1FFF);

    // Extract triangular indices.
    float temp = gsB2 - 8 * mantissa;
    ushort usY = (ushort)Mathf.Floor(0.5f * (gsB - Mathf.Sqrt(Mathf.Abs(temp))));
    ushort usX = (ushort)(mantissa - ((usY * (255 - usY)) >> 1));

    var normal = Vector3.zero;

    // Build approximate normal.
    normal.x = usX * gsInvFactor;
    normal.y = usY * gsInvFactor;
    temp = 1.0f - normal.x * normal.x - normal.y * normal.y;
    normal.z = Mathf.Sqrt(Mathf.Abs(temp));

    // Determine octant.
    if ((index & 0x8000) != 0)
    {
    normal.x = -normal.x;
    }
    if ((index & 0x4000) != 0)
    {
    normal.y = -normal.y;
    }
    if ((index & 0x2000) != 0)
    {
    normal.z = -normal.z;
    }

    return normal;
    }
    }