Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Light range in forward shader

Discussion in 'Shaders' started by Zicandar, May 20, 2015.

  1. Zicandar

    Zicandar

    Joined:
    Feb 10, 2014
    Posts:
    388
    Hello!
    I'm working on a modified unity standard shader, one of the things I'm changing is light falloff, and for this I need to know the range of the light. (I need it working in forward mode also, it works flawlessly in deferred!)
    And before you suggest I replace their texture, I know this can be done, but would much prefer not to.

    I thought I had found a solution by using: _LightMatrix0[0][0] is 1 / range. (At least for point lights)
    BUT for some lights this works, for others it does not... This is beacuse as soon as the light is rotated it breaks!

    They have this variable in the UnityShaderVariables.cginc
    Code (CSharp):
    1. uniform float4 _LightPositionRange; // xyz = pos, w = 1/range
    BUT it's never filled!
    _WorldSpaceLightPos0 is however filled with the correct position but no useful .w variable. (Seems to always be 1 for a point light as stated in the vertex shader)

    In deferred it's quite simple to get it:
    _LightPos has the layout // xyz = pos, w = 1/range

    However in forward mode they use a "macro"
    LIGHT_ATTENUATION(i)
    And that uses some light data that another macro in the vertex shader has created.
    In summary they use a Matrix for this, and then work in "light space". So pos [0,0,0] would be the center of the light, and at length = 1 away from it your at it's range. (Or so I'd assume at least).
    This results in me not being able to get the data I wan't from the light >.<.
    Also note that unity 5 still uses stuff they write as unity 4.x stuff...

    That uses some light helpers tagged as
    Code (CSharp):
    1. // -----------------------------
    2. //  Light helpers (4.x version)
    3. // -----------------------------
    4.  
    5. // This version computes light coordinates in the vertex shader and passes them to the fragment shader.
    6.  
    7. #ifdef POINT
    8. #define LIGHTING_COORDS(idx1,idx2) unityShadowCoord3 _LightCoord : TEXCOORD##idx1; SHADOW_COORDS(idx2)
    9. #define TRANSFER_VERTEX_TO_FRAGMENT(a) a._LightCoord = mul(_LightMatrix0, mul(_Object2World, v.vertex)).xyz; TRANSFER_SHADOW(a)
    10. #define LIGHT_ATTENUATION(a)    (tex2D(_LightTexture0, dot(a._LightCoord,a._LightCoord).rr).UNITY_ATTEN_CHANNEL * SHADOW_ATTENUATION(a))
    11. #endif
    While the things marked 5.x helpers are unusued:
    Code (CSharp):
    1. // ------------------------------
    2. //  Light helpers (5.0+ version)
    3. // ------------------------------
    4.  
    5. // This version depends on having worldPos available in the fragment shader and using that to compute light coordinates.
    6.  
    7. // If none of the keywords are defined, assume directional?
    8. #if !defined(POINT) && !defined(SPOT) && !defined(DIRECTIONAL) && !defined(POINT_COOKIE) && !defined(DIRECTIONAL_COOKIE)
    9. #define DIRECTIONAL
    10. #endif
    11.  
    12.  
    13. #ifdef POINT
    14. uniform sampler2D _LightTexture0;
    15. uniform unityShadowCoord4x4 _LightMatrix0;
    16. #define UNITY_LIGHT_ATTENUATION(destName, input, worldPos) \
    17.     unityShadowCoord3 lightCoord = mul(_LightMatrix0, unityShadowCoord4(worldPos, 1)).xyz; \
    18.     fixed destName = (tex2D(_LightTexture0, dot(lightCoord, lightCoord).rr).UNITY_ATTEN_CHANNEL * SHADOW_ATTENUATION(input));
    19. #endif
    Now the color of the light I have to get in yet another place!
    Code (CSharp):
    1. fixed4 _LightColor0;
    Note a couple of things, it's a Fixed, (and I'm pretty sure unity multiplies in intensity before sending it to the shader), it's in a different file: UnityLightingCommon.cginc
    And in this file it also has a fixed4 _SpecColor and some UnityGI structs.
     
    Last edited: May 20, 2015
  2. Zicandar

    Zicandar

    Joined:
    Feb 10, 2014
    Posts:
    388
    Solution that seems to work for point lights at least:
    Code (CSharp):
    1. float3 lightScale = float3(_LightMatrix0[0][0], _LightMatrix0[1][0], _LightMatrix0[2][0]);
    2. float res = dot(lightScale, lightScale);
    Now note that res is 1 / (radius * radius) if I haven't made any misstakes.
     
  3. ArachnidAnimal

    ArachnidAnimal

    Joined:
    Mar 3, 2015
    Posts:
    1,760
    Would your solution also help with baking of point lights?
    I have baked a point light, but it seems that the falloff is not correct. The point light is treated more like a spotlight pointed directly at the surface:
    pointlight.png
    i am not getting a smooth fade no matter how I position the light.
    Then I noticed this thread:
    http://answers.unity3d.com/questions/421402/i-got-problems-with-baked-lightsshadows-any-help.html
    Does this relate to the issues you are discussing?

    but then making slight adjustments to the intensity yields completely different falloff appearances:


    reducedIntensity.png
    i reduced the intensity from 2 to 1.5, now the falloff is much smoother. This is a huge difference.
     
    Last edited: May 24, 2015
  4. Zicandar

    Zicandar

    Joined:
    Feb 10, 2014
    Posts:
    388
    I have not worked with baked lights, but my changes shouldn't have any effect for that. As baking is most likely done in a way that ignores the shaders. But I could easily be very wrong here!
    If modifying intensity down gives a better falloff, maybe you need a higher range on the light?
     
  5. Deleted User

    Deleted User

    Guest