Search Unity

Why does LightingBlinnPhong_DirLightmap not use mul to calculate lightDir?

Discussion in 'Shaders' started by Bas-Smit, Dec 19, 2014.

  1. Bas-Smit

    Bas-Smit

    Joined:
    Dec 23, 2012
    Posts:
    274
    Looking at line 124 in Lighting.cginc (version 4.6.1) we see the following line:

    half3 lightDir = normalize (scalePerBasisVector.x * unity_DirBasis[0] + scalePerBasisVector.y * unity_DirBasis[1] + scalePerBasisVector.z * unity_DirBasis[2]);

    where scalePerBasisVector is a half3 and unity_DirBasis is a float3x3. Unless I'm completely mistaken this could also be written as:

    half3 lightDir = normalize(mul(scalePerBasisVector, unity_DirBasis));

    I see absolutely no difference if I output the lightDir when shading a complex mesh in a complex lighting environment. I can imagine a compiler can produce more efficient byte code with the latter which seems to be confirmed by looking at the "Stats for Fragment shader" when viewing the compiled shader:

    // d3d9 : 45 math, 4 texture vs // d3d9 : 44 math, 4 texture

    Any ideas?
     
  2. BBeck

    BBeck

    Joined:
    Jan 12, 2014
    Posts:
    57
    Won't the original multiply the half3 vector by only one row(or column) of the float3x3 matrix? Multiplying by the entire matrix will give a completely different result than multiplying only by one row or column.

    If it works, it must be because the other 2 are basically "empty". I believe that if the other 2 are set to 1 they won't affect the answer.
     
  3. Bas-Smit

    Bas-Smit

    Joined:
    Dec 23, 2012
    Posts:
    274
    Ehm, I dont think so the entire matrix is used:

    scalePerBasisVector.x * unity_DirBasis[0]
    scalePerBasisVector.y * unity_DirBasis[1]
    scalePerBasisVector.z * unity_DirBasis[2]
     
  4. BBeck

    BBeck

    Joined:
    Jan 12, 2014
    Posts:
    57
    Isn't [0] just one of the 9 elements in the matrix? I'm imagining that would turn it into a 1 dimensional array with values [0] through [8] rather than the 2 dimensional matrix of [0][0] through [2][2].

    If it's an entire row or column with [0], then you're probably right.

    I'm not at all certain without trying it, but I would think that it is one element of the matrix rather than an entire row or column.
     
  5. Bas-Smit

    Bas-Smit

    Joined:
    Dec 23, 2012
    Posts:
    274
    No, individual values are accessed like so: M._m00
     
  6. BBeck

    BBeck

    Joined:
    Jan 12, 2014
    Posts:
    57
    Then you're probably right. I haven't had to do a lot of matrix algebra lately, but I think either way you're just multiplying each x,y,z coordinate times each individual element of the matching row to produce a new x,y,z value.

    Perhaps the person who wrote it was not comfortable with vectors and went out of their way to try and not look at it as a vector times a matrix. Unity is great in that it allows beginners to get started. But that's also one of its downfalls in that you have a lot of beginners who don't know how to do things properly and don't understand even the basics of matrix algebra and such.

    But it's all good. We all have to start somewhere. I certainly would have written it more like what you are saying.

    For what it's worth. Here is my Blinn-Phong smooth shader. It's in HLSL and Unity does Cg instead, but the concept is basically the same.
    Code (csharp):
    1.  
    2. float4 SmoothPixelShaderFunction(SmoothVertexShaderOutput Input) : SV_TARGET
    3. {
    4. float3 LightDirection;
    5. float DiffuseLightPercentage;
    6. float4 OutputColor;
    7. float4 SpecularColor;
    8. float3 CameraDirection; //Float3 because the w component really doesn't belong in a 3D vector normal.
    9. float4 AmbientLight;
    10. float4 DiffuseLight;
    11. float4 Texel;
    12. LightDirection = -DiffuseLightDirection; //Normal must face into the light, rather than WITH the light to be lit up.
    13. DiffuseLightPercentage = saturate(dot(Input.Normal, LightDirection)); //Percentage is based on angle between the direction of light and the vertex's normal.
    14. DiffuseLight = saturate((DiffuseLightColor * Input.Color) * DiffuseLightPercentage); //Apply only the percentage of the diffuse color. Saturate clamps output between 0.0 and 1.0.
    15. CameraDirection = normalize(CameraPosition - Input.WorldSpacePosition); //Create a normal that points in the direction from the pixel to the camera.
    16. if (DiffuseLightPercentage == 0.0f)
    17. {
    18. SpecularColor = float4(0.0f, 0.0f, 0.0f, 1.0f);
    19. }
    20. else
    21. {
    22. //SpecularColor = BlinnSpecular(LightDirection, DiffuseLightColor, Input.Normal, CameraDirection, 45.0f);
    23. SpecularColor = PhongSpecular(LightDirection, DiffuseLightColor, Input.Normal, CameraDirection, 35.0f);
    24. }
    25. Texel = tex2D(TextureSampler, Input.UV);
    26. Texel.a = 1;
    27. //OutputColor = saturate((AmbientLightColor * Input.Color) + DiffuseLight * DiffuseLightPercentage + SpecularColor);
    28. OutputColor = saturate(AmbientLightColor + Input.Color + Texel * DiffuseLightPercentage + SpecularColor);
    29. //OutputColor = saturate(Texel);
    30.  return OutputColor;
    31. }
    32.  
    33.  
    34. float4 BlinnSpecular(float3 LightDirection, float4 LightColor, float3 PixelNormal, float3 CameraDirection, float SpecularPower)
    35. {
    36. float3 HalfwayNormal;
    37. float4 SpecularLight;
    38. float SpecularHighlightAmount;
    39. HalfwayNormal = normalize(LightDirection + CameraDirection);
    40. SpecularHighlightAmount = pow(saturate(dot(PixelNormal, HalfwayNormal)), SpecularPower);
    41. SpecularLight = SpecularHighlightAmount * LightColor;
    42. return SpecularLight;
    43. }
    44. float4 PhongSpecular(float3 LightDirection, float4 LightColor, float3 PixelNormal, float3 CameraDirection, float SpecularPower)
    45. {
    46. float3 ReflectedLightDirection;
    47. float4 SpecularLight;
    48. float SpecularHighlightAmount;
    49. ReflectedLightDirection = 2.0f * PixelNormal * saturate(dot(PixelNormal, LightDirection)) - LightDirection;
    50. SpecularHighlightAmount = pow(saturate(dot(ReflectedLightDirection, CameraDirection)), SpecularPower);
    51. SpecularLight = SpecularHighlightAmount * LightColor;
    52. return SpecularLight;
    53. }
    54.  
     
  7. Bas-Smit

    Bas-Smit

    Joined:
    Dec 23, 2012
    Posts:
    274
    This is from the Unity builtin shaders, I can assure you the person who wrote this is _very_ familiar with matrices ;)