Search Unity

Shader Graph - Light Direction

Discussion in 'Shaders' started by Sark_Klimento, Jan 19, 2019.

  1. Sark_Klimento

    Sark_Klimento

    Joined:
    Jan 17, 2019
    Posts:
    12
    So i want to somehow get the _WorldSpaceLightPos0 value (basic in the default shaders) or Main Light Direction at least. Any ideas how can i get it ?

    I tried to use the custom shader graph node that gets the _WorldSpaceLightPos0 by using shader code, but it seems not working because the _WorldSpaceLightPos0 variable is not found.
     
  2. Ubawesome

    Ubawesome

    Joined:
    Jul 18, 2015
    Posts:
    8
    Found this on github. Custom node that's been working splendidly for Unity 2018.3.
    Would credit the original author, but I can't seem to find the post.

    Code (CSharp):
    1.  
    2. using UnityEngine;
    3. using UnityEditor.ShaderGraph;
    4. using System.Reflection;
    5.  
    6. // IMPORTANT:
    7. // - tested with LWRP and Shader Graph 4.6.0-preview ONLY
    8. // - likely to break in SG 5.x and beyond
    9. // - for HDRP, add your own keyword to detect environment
    10. [Title("Input", "Lighting", "Main Light Data")]
    11. public class MainLightDataNode : CodeFunctionNode
    12. {
    13.     // shader code definition
    14.     // handle shader graph editor environment where main light data isn't defined
    15.     private static string shaderText = @"{
    16.        #ifdef LIGHTWEIGHT_LIGHTING_INCLUDED
    17.            Light mainLight = GetMainLight();
    18.            Color = mainLight.color;
    19.            Direction = mainLight.direction;
    20.            Attenuation = mainLight.distanceAttenuation;
    21.        #else
    22.            Color = float3(1.0, 1.0, 1.0);
    23.            Direction = float3(0.0, 1.0, 0.0);
    24.            Attenuation = 1.0;
    25.        #endif
    26.    }";
    27.  
    28.     // disable own preview as no light data in shader graph editor
    29.     public override bool hasPreview
    30.     {
    31.         get
    32.         {
    33.             return false;
    34.         }
    35.     }
    36.  
    37.     // declare node
    38.     public MainLightDataNode()
    39.     {
    40.         name = "Main Light Data";
    41.     }
    42.  
    43.     // reflection to shader function
    44.     protected override MethodInfo GetFunctionToConvert()
    45.     {
    46.         return GetType().GetMethod(
    47.             "GetMainLightData",
    48.             BindingFlags.Static | BindingFlags.NonPublic
    49.         );
    50.     }
    51.  
    52.     // shader function and port definition
    53.     private static string GetMainLightData(
    54.         [Slot(0, Binding.None)] out Vector3 Color,
    55.         [Slot(1, Binding.None)] out Vector3 Direction,
    56.         [Slot(2, Binding.None)] out Vector1 Attenuation
    57.     )
    58.     {
    59.         // define vector3
    60.         Direction = Vector3.zero;
    61.         Color = Vector3.zero;
    62.  
    63.         // actual shader code
    64.         return shaderText;
    65.     }
    66. }
     
  3. Sark_Klimento

    Sark_Klimento

    Joined:
    Jan 17, 2019
    Posts:
    12
    I already seen this, but it seems not work for me - the LIGHTWEIGHT_LIGHTING_INCLUDED is always false for some reason, so i get no info. Also when i call GetMainLight it prints that it cannot find any sequense....
     
    ruben-nunez likes this.
  4. Ubawesome

    Ubawesome

    Joined:
    Jul 18, 2015
    Posts:
    8
    Hmm, that's pretty strange. This is a fixed version of the original custom node, so it might be that you were using the old one.
    Unfortunately, if your googling didn't turn up anything, mine probably won't either, sorry.
    Good luck!
     
  5. toothbrush

    toothbrush

    Joined:
    Mar 24, 2017
    Posts:
    2
    You can simply add a property that reference to that build-in parameter, if your pipeline have that variable setup.
    lightposVector.PNG
     
  6. Opaqueplacebo

    Opaqueplacebo

    Joined:
    Oct 15, 2018
    Posts:
    5
    I'm wondering if there is any work around for Shader Graph 5.x?
     
  7. windd123

    windd123

    Joined:
    Jun 7, 2018
    Posts:
    1
    So you can access light direction by using _WorldSpaceLightPos0, what about attenuation, which is needed for the object to receive shadows?
     
    HKesim and Gekigengar like this.
  8. Jarestrepogu

    Jarestrepogu

    Joined:
    Feb 18, 2018
    Posts:
    9
    Amazing!
    It does the trick, thanks man!
     
  9. WendelinReich

    WendelinReich

    Joined:
    Dec 22, 2011
    Posts:
    228
    Hmmm, can't get this trick to work on my system (2019.1 with latest LWRP). Could that be because I don't have that "variable setup", whatever that means?
     
  10. Jarestrepogu

    Jarestrepogu

    Joined:
    Feb 18, 2018
    Posts:
    9
    I did nothing strange, I just created a vector 4 property named "_WorldSpaceLightPos0" and set it to be hidden in the inspector. I used 2019.1 and the latest LWRP as well.
    By the way, I noticed the ShaderGraph window is very slow in the last version of LWRP, has anyone experienced the same?
     
  11. Arafuin

    Arafuin

    Joined:
    Jan 9, 2018
    Posts:
    1
    Any news about this? The vector 4 property named "_WorldSpaceLightPos0" does the trick, but it doesn't receive cast shadows. I dont understand how this shader graph doesn't have the most basic functions
     
    Gekigengar likes this.
  12. pbritton

    pbritton

    Joined:
    Nov 14, 2016
    Posts:
    160
    Is there any update with regards to getting light direction in shader graph for HDRP?
     
  13. pauldrummond

    pauldrummond

    Joined:
    Oct 30, 2014
    Posts:
    145
    Really could do with this for shader graph in HDRP. I hope it appears soon.
     
  14. pbritton

    pbritton

    Joined:
    Nov 14, 2016
    Posts:
    160
    Any update on this feature for HDRP?
     
    nehvaleem and anthony-pinskey like this.
  15. pbritton

    pbritton

    Joined:
    Nov 14, 2016
    Posts:
    160
    More than a month later, no answer to when or how to access light position or direction.
     
  16. Invertex

    Invertex

    Joined:
    Nov 7, 2013
    Posts:
    1,550
    I'd imagine there will be a stable way to access it in HDRP once HDRP is no longer in such an experimental state. But, HDRP is also a drastically more complicated renderer than LWRP and lighting something isn't quite as simple as just getting a light if you want other elements in the scene to affect the lighting on this object too.
     
  17. Nothke

    Nothke

    Joined:
    Dec 2, 2012
    Posts:
    112
    Hi, sorry for bumping the thread. Putting this because other people might need it. You can obtain the HDRP directional light with this HLSL:

    Code (CSharp):
    1.  
    2. #ifndef GETLIGHT_INCLUDED
    3. #define GETLIGHT_INCLUDED
    4.  
    5. #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl"
    6. #include "Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightDefinition.cs.hlsl"
    7.  
    8. void GetSun_float(out float3 lightDir, out float3 color)
    9. {
    10. #if SHADERGRAPH_PREVIEW
    11.     lightDir = float3(0.707, 0.707, 0);
    12.     color = 1;
    13. #else
    14.     if (_DirectionalLightCount > 0)
    15.     {
    16.         DirectionalLightData light = _DirectionalLightDatas[0];
    17.         lightDir = -light.forward.xyz;
    18.         color = light.color;
    19.     }
    20.     else
    21.     {
    22.         lightDir = float3(1, 0, 0);
    23.         color = 0;
    24.     }
    25. #endif
    26. }
    27.  
    28. #endif
    29.  

    Save it as GetLight.HLSL, and then you can obtain direction and color in custom function node, reference the file and use GetSun, set 2 vector outputs as in the function out parameters.

    Unity_2019-11-12_14-30-24.png

    You can of course wrap the function node in a subgraph so that you can easily add it to other graphs:

    Unity_2019-11-12_14-40-03.png Unity_2019-11-12_14-39-38.png

    In my case I needed direction and color (which includes intensity), but you can use a bunch of other light parameters, take a look at <HD Package Dir>\Runtime\Lighting\LightDefinition.cs.hlsl.
     
    Last edited: Nov 12, 2019
  18. pauldrummond

    pauldrummond

    Joined:
    Oct 30, 2014
    Posts:
    145
    I tried writing a custom node to get light direction when starting on this. Will investigate again with your code. Thanks.

    UPDATE: I tried this but am getting the usual errors about 'light' being undeclared. Are you creating unexposed shader properties as well?
     
    Last edited: Nov 12, 2019
  19. Nothke

    Nothke

    Joined:
    Dec 2, 2012
    Posts:
    112
    You know what, I wanted to move the hlsl to another folder so I can pack it and send it to you, and now I'm getting "undeclared identifier" bug too. I think this is a bug with the shader graph because it works in the subgraph but not in the graph that is using the subgraph. So annoying.
     
  20. Nothke

    Nothke

    Joined:
    Dec 2, 2012
    Posts:
    112
    @pauldrummond ok, The files strangely kept rebuilding themselves even if I kept deleting them, and there were multiple copies of "GetLight.hlsl" which I think was the problem. Also the function node doesn't seem to keep the file reference after you move it, you have to reassign it every time. I restarted Unity (a few times) and now it works again.

    See the zip below. Try dropping the subgraph into your shader and hopefully it will work.

    Edit: sorry about the 128000 default color in the graph, I'm using real lux values with exposure so the sun is 128000 (in shader preview only), you can change it in the hlsl.
     

    Attached Files:

    Last edited: Nov 12, 2019
  21. pauldrummond

    pauldrummond

    Joined:
    Oct 30, 2014
    Posts:
    145
    Thanks. I'll try these files.
     
  22. JanKrocak

    JanKrocak

    Joined:
    Jul 11, 2021
    Posts:
    13
    Thanks a lot @Nothke !
    Your custom hlsl worked great for me in HDRP.
     
  23. ksicotte

    ksicotte

    Joined:
    Apr 26, 2021
    Posts:
    4
    Hey, I am tying to make it work. I am on Unity 2020.3.01, but it seems to not recognize "_DirecitonalLightCount" and "DirectionalLightDatas[0]'. For you it work as is?
     
  24. Lucospade

    Lucospade

    Joined:
    Aug 23, 2014
    Posts:
    4
    For anyone who is struggling to implement this - the main function in the HLSL code is erroneously named GetSun - change it to GetLight and you're good to go.
     
    ksicotte likes this.
  25. Passeridae

    Passeridae

    Joined:
    Jun 16, 2019
    Posts:
    395
    Hi!
    Does anyone know how to get direction (or position) for other type of lights? I'm interested in point and area lights.
    Thanks!
     
  26. AtomicIsland

    AtomicIsland

    Joined:
    Sep 20, 2018
    Posts:
    12
    I am also having this problem in Unity 2020.3.15f2.
     
  27. junkt3st

    junkt3st

    Joined:
    Mar 26, 2022
    Posts:
    3
    I'm working with urp v 12.1.7 and I think I've had some success getting at least the main light direction and color.
    In my case, this is all I need right now.
    I've defined a custom function node called GetSun that looks like this in its own hlsl file


    Code (CSharp):
    1. #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
    2.  
    3. void GetSun_float3(out float3 Direction, out half3 Color)
    4. {
    5.     Light sun = GetMainLight();
    6.     Direction = sun.direction;
    7.     Color = sun.color;
    8. }
    This seeems to be working fine except I'm getting a weird error exclusively in shader graph claiming that there's a "Redefinition of _Time on line 40" and I can't find what the hell its talking about.
    It seems to be working okay though.
     
  28. Invertex

    Invertex

    Joined:
    Nov 7, 2013
    Posts:
    1,550
    The issue is probably the include of Lighting.hlsl which then includes other include files and ends up re-defining _Time.
    You don't actually need Lighting.hlsl for this, the GetMainLight() function is inside of RealtimeLights.hlsl.

    So at the top, instead of that #include line, you can try:

    Code (CSharp):
    1. #ifndef UNIVERSAL_REALTIME_LIGHTS_INCLUDED
    2.     #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/RealtimeLights.hlsl"
    3. #endif
    Using the #ifndef we can also avoid potential re-includes of the same file, as that macro is defined in the RealtimeLights.hlsl file.
     
    Last edited: Aug 24, 2022
  29. junkt3st

    junkt3st

    Joined:
    Mar 26, 2022
    Posts:
    3
    Thanks for the tip!
    I just tried this and got the same problem. I traced all of the includes, and wasn't able to find where _Time is being (re)defined anywhere.
    Additionally, I even tried only including .../ShaderLibrary/Input.hlsl and accessing _MainLightPosition, and still I'm getting the redefinition error.
     
    Last edited: Aug 24, 2022
  30. junkt3st

    junkt3st

    Joined:
    Mar 26, 2022
    Posts:
    3
    I found the problem.
    _Time is defined in "Packages/com.unity.render-pipelines.universal/ShaderLibrary/RealtimeLights.hlsl" which is included in .../Input.hlsl which is included in .../RealtimeLights.hlsl
    No idea how to get around this.
    It's not causing any problems in my shader yet, but I'm worried it will if I want to animate things using _Time.
     
  31. Invertex

    Invertex

    Joined:
    Nov 7, 2013
    Posts:
    1,550
    It shouldn't cause an issue because it's just a warning and there is still only going to be one actual definition of _Time that is being set as a global shader value.

    I do wonder what the rationale of Unity is to not wrap their include code inside the #ifndef statements each include file has at their header already so that no matter what it's never defined twice. I don't believe there should be any downside to that... But I probably am missing some edge case issue. Would you have insight into this @aleksandrk ?
     
  32. aleksandrk

    aleksandrk

    Unity Technologies

    Joined:
    Jul 3, 2017
    Posts:
    3,025
    The include guard (#ifndef FOO / #define FOO / <include code> / #endif) should be enough. When it's present in the include file, wrapping the #include directive in the same conditional is redundant and makes it harder to maintain the code.

    I guess the problem here is that it's defined in two different files: once for Shader Graph (in ShaderGraphLibrary/ShaderVariables.hlsl) and once in URP (ShaderLibrary/UnityInput.hlsl).
     
  33. Invertex

    Invertex

    Joined:
    Nov 7, 2013
    Posts:
    1,550
    Oh no I wasn't referring to wrapping the #include directives themselves, but the code that is inside of the included file inside the define it already creates.... But it seems it already does do that and I misremembered. It is indeed the issue as you say.
    And probably not worth a bug report right, since it's not really something that can be easily avoided between these systems I'd imagine.
     
  34. aleksandrk

    aleksandrk

    Unity Technologies

    Joined:
    Jul 3, 2017
    Posts:
    3,025
    Indeed.
     
  35. Raymond_XJTU

    Raymond_XJTU

    Joined:
    Jul 24, 2021
    Posts:
    3