Search Unity

  1. Unity 2019.1 beta is now available.
    Dismiss Notice
  2. The Unity Pro & Visual Studio Professional Bundle gives you the tools you need to develop faster & collaborate more efficiently. Learn more.
    Dismiss Notice
  3. We're looking for insight from anyone who has experience with game testing to help us better Unity. Take our survey here. If chosen to participate you'll be entered into a sweepstake to win an Amazon gift card.
    Dismiss Notice
  4. Want to provide direct feedback to the Unity team? Join the Unity Advisory Panel.
    Dismiss Notice
  5. Unity 2018.3 is now released.
    Dismiss Notice
  6. Improve your Unity skills with a certified instructor in a private, interactive classroom. Watch the overview now.
    Dismiss Notice

Question about L2 spherical harmonics calculation in UnityCG.cginc

Discussion in 'Shaders' started by Darkisu, Feb 11, 2019 at 10:38 AM.

  1. Darkisu


    Oct 24, 2018
    I noticed a spherical harmonics calculation in UnityCG.cginc where the L2 spherical harmonics lighting decompression was calculated as below:

    half4 vB = normal.xyzz * normal.yzzx;
    x1.r = dot(unity_SHBr,vB);
    x1.g = dot(unity_SHBg,vB);
    x1.b = dot(unity_SHBb,vB);

    My question is that according to this Wikipedia page, the calculation of Y(2, 0) is :
    SH Y20.JPG
    Then why is the SHEvalLinearL2(half4 normal) function calculate Y(2, 0) simply multiplying Z^2 with a value?
    Won't it cause the result contribution among Z axis a little bit stronger than other two axis?
  2. jvo3dc


    Oct 11, 2013
    There is the mathematical formula of spherical harmonics and then there is the practical one. In the conversion, a few things commonly happen:
    - The constant multiplier is removed or simplified, which doesn't actually change the result. The main importance is that the values fall in the target range if needed. (For example 0 to 1 if needed by the texture/rendertexture.)
    - The harmonics are reordered, which also doesn't change the result. This to maximize vector operations. (Like normal.xyzz * normal.yzzx)

    Without the constant multipliers and assuming r=1 (normalized normal vector), the L2 SH coefficients are:
    • 1
    • y
    • z
    • x
    • xy
    • yz
    • 2zz-xx-yy
    • xz
    • xx-yy
    Besides reordering, the only one that is different in Unity is indeed 2zz-xx-yy, which is just implemented as zz. If I look at the contour of the original formula, I can understand the optimization:

    (Third row, middle image)

    The zz approximation loses the (negative) yellow torus, but maintains the double peak at positive and negative z. In essence, it just adds Y0,0 to Y2,0:
    • 1 = xx+yy+zz
    • 2zz-xx-yy + 1 =
    • 2zz-xx-yy+xx+yy+zz =
    • 3zz
    If you then rescale again, you end up with just z^2, which written differently is:
    • z^2 = A*Y2,0 + B*Y0,0 (for specific values of A and B.)
    Darkisu and Invertex like this.