Search Unity

How to get the position of a point Light into a shader

Discussion in 'Shaders' started by Korido, Mar 1, 2021.

  1. Korido

    Korido

    Joined:
    Jan 29, 2020
    Posts:
    2
    Hello everyone,
    I got a game project in wich one the player has to find his way into the dark world. to do it he got a point light that illuminate around him.
    For some gameplay reason i want the light very binary, everything in the range of the light is white and everything out of the range is black (little bit like in White Night).
    To make it, i need to get the position of my point light.
    I read that I should use _WorldSpaceLightPos0
    I am using this code:

               
    fixed4 frag (v2f i) : SV_Target
    {
    float3 LightPos= _WorldSpaceLightPos0;
    return float4 (LightPos.xyz, 1);
    }


    in theory it should render me a unique color linked on the position of my PointLight, but it doesn't work, it only render me a color according to the direction of a directionnal Light but if i only got my point light it doesn't work.


    So i don't understand how to make the _WorldSpaceLightPos0 picking me the position of my pointlight and not the direction of a directionnal light.


    I don't know if my problem is understandable, but if you read it and you dont understand ask me more clarification.
    Thanks to read.
     

    Attached Files:

  2. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,348
    You're going to want to go through some tutorials on how Unity's lighting system works. However the short version is Unity's built in forward renderer uses multiple passes to render multiple lights. The first "ForwardBase" pass only renders the main directional light, reflections, and ambient lighting or baked lighting. All additional lights are rendered using the "ForwardAdd" pass, which re-renders the entire object again for each additional light. In the base pass
    _WorldSpaceLightPos0
    is always the directional light, and if there is no directional light then it is still set with an arbitrary normalized vector still, just with
    _LightColor0
    set to black. In the add pass
    _WorldSpaceLightPos0
    is the position or direction of the light depending on if it's a punctual light (spot or point) or a directional light.

    https://catlikecoding.com/unity/tutorials/rendering/

    You also do need a base pass. You can't just have an add pass. However the base pass can render a solid black if you never want ambient or directional lighting. But if you want to be able to have custom point lights, you'll need to have an add pass where you handle them. If you want something where multiple lights interact with each other, Unity's forward renderer doesn't really allow for that since the lights will be separate passes.
    ...

    Technically Unity also has "per vertex" aka "non-important" lights that the base pass also has access too. Up to 4 per object. Typically these are calculated per vertex and are referred to as per vertex lights in Unity's shader code, but on the light component they're enabled by setting its "Render Mode" to "Non-important". However it is possible to use these lights per pixel in a custom shader. But there are some issues when doing so.

    First is Unity's per vertex lights are encoded in a way that they don't actually give the shader the lights' radii. Their "radius" is controlled by a tweaked infinite falloff curve and the light's brightness balanced to try to approximate a per pixel light, but doesn't match it. However a while back I reverse engineered the value it passed to the shader to be able to reconstruct the original range. It works, but it's kind of a nasty bit of code.
    https://forum.unity.com/threads/vertex-lights-culling-vs-falloff-mismatch.757817/#post-5050547

    Second is Unity's shader compiler seems to not expect you to use per vertex lights in the fragment shader, and while it will still supply per vertex lighting information to the shader properly when there are lights affecting it, it sends bogus data to objects that are not affected by per vertex lights. To deal with that you need to do something like this:
    Code (csharp):
    1. // up with the rest of your multi_compile lines, like #pragma multi_compile_fwdbase
    2. #pragma multi_compile _ VERTEXLIGHT_ON
    3.  
    4. // then in the fragment shader were you handle per vertex lights
    5. half3 additiveLights = 0.0;
    6. #if defined(VERTEXLIGHT_ON)
    7. additiveLights = Shade4PointLights(// stuff);
    8. #endif
     
    AcidArrow likes this.
  3. Korido

    Korido

    Joined:
    Jan 29, 2020
    Posts:
    2
    Thank you a lot for your complete and fast answer. I understand more the problem, i am gonna look at the resources you gave me. And I apply what u said. I told u when i fix the issue.