Skip to content

Instantly share code, notes, and snippets.

@bitinn
Forked from ciro-unity/MainLightNode.cs
Last active August 11, 2023 08:15
Show Gist options
  • Save bitinn/72922a0a69f6d723d94e94f2fc21230e to your computer and use it in GitHub Desktop.
Save bitinn/72922a0a69f6d723d94e94f2fc21230e to your computer and use it in GitHub Desktop.

Revisions

  1. bitinn revised this gist Dec 17, 2018. 1 changed file with 2 additions and 3 deletions.
    5 changes: 2 additions & 3 deletions MainLightDataNode.cs
    Original file line number Diff line number Diff line change
    @@ -10,10 +10,9 @@
    [Title("Custom", "Main Light Data")]
    public class MainLightDataNode : CodeFunctionNode {
    // shader code definition
    // handle shader graph environment where light data isn't defined
    // exclude shader graph master node preview where light data is defined
    // handle shader graph editor environment where main light data isn't defined
    private static string shaderText = @"{
    #if defined(LIGHTWEIGHT_LIGHTING_INCLUDED) && !defined (UNITY_GRAPHFUNCTIONS_LW_INCLUDED)
    #ifdef LIGHTWEIGHT_LIGHTING_INCLUDED
    Light mainLight = GetMainLight();
    Color = mainLight.color;
    Direction = mainLight.direction;
  2. bitinn revised this gist Dec 17, 2018. 1 changed file with 3 additions and 2 deletions.
    5 changes: 3 additions & 2 deletions MainLightDataNode.cs
    Original file line number Diff line number Diff line change
    @@ -10,9 +10,10 @@
    [Title("Custom", "Main Light Data")]
    public class MainLightDataNode : CodeFunctionNode {
    // shader code definition
    // handle shader graph editor environment where main light data isn't defined
    // handle shader graph environment where light data isn't defined
    // exclude shader graph master node preview where light data is defined
    private static string shaderText = @"{
    #ifdef LIGHTWEIGHT_LIGHTING_INCLUDED
    #if defined(LIGHTWEIGHT_LIGHTING_INCLUDED) && !defined (UNITY_GRAPHFUNCTIONS_LW_INCLUDED)
    Light mainLight = GetMainLight();
    Color = mainLight.color;
    Direction = mainLight.direction;
  3. bitinn revised this gist Dec 14, 2018. 2 changed files with 60 additions and 89 deletions.
    60 changes: 60 additions & 0 deletions MainLightDataNode.cs
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,60 @@

    using UnityEngine;
    using UnityEditor.ShaderGraph;
    using System.Reflection;

    // IMPORTANT:
    // - tested with LWRP and Shader Graph 4.6.0-preview ONLY
    // - likely to break in SG 5.x and beyond
    // - for HDRP, add your own keyword to detect environment
    [Title("Custom", "Main Light Data")]
    public class MainLightDataNode : CodeFunctionNode {
    // shader code definition
    // handle shader graph editor environment where main light data isn't defined
    private static string shaderText = @"{
    #ifdef LIGHTWEIGHT_LIGHTING_INCLUDED
    Light mainLight = GetMainLight();
    Color = mainLight.color;
    Direction = mainLight.direction;
    Attenuation = mainLight.distanceAttenuation;
    #else
    Color = float3(1.0, 1.0, 1.0);
    Direction = float3(0.0, 1.0, 0.0);
    Attenuation = 1.0;
    #endif
    }";

    // disable own preview as no light data in shader graph editor
    public override bool hasPreview {
    get {
    return false;
    }
    }

    // declare node
    public MainLightDataNode () {
    name = "Main Light Data";
    }

    // reflection to shader function
    protected override MethodInfo GetFunctionToConvert () {
    return GetType().GetMethod(
    "GetMainLightData",
    BindingFlags.Static | BindingFlags.NonPublic
    );
    }

    // shader function and port definition
    private static string GetMainLightData (
    [Slot(0, Binding.None)] out Vector3 Color,
    [Slot(1, Binding.None)] out Vector3 Direction,
    [Slot(2, Binding.None)] out Vector1 Attenuation
    ) {
    // define vector3
    Direction = Vector3.zero;
    Color = Vector3.zero;

    // actual shader code
    return shaderText;
    }
    }
    89 changes: 0 additions & 89 deletions MainLightNode.cs
    Original file line number Diff line number Diff line change
    @@ -1,89 +0,0 @@
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEditor.ShaderGraph;
    using System.Reflection;

    [Title("Custom", "Main Light")]
    public class MainLightNode : CodeFunctionNode
    {
    public override bool hasPreview {get {return false;}}

    //This is the string that's passed into the code of the real, final shader code that is used in the Scene when you hit Apply in the ShaderGraph window.
    //As such, it will use real light data from the Scene (for instance, GetMainLight()).
    private static string functionBodyForReals = @"{
    Light mainLight = GetMainLight();
    Color = mainLight.color;
    Direction = mainLight.direction;
    float4 shadowCoord;
    #ifdef _SHADOWS_ENABLED
    #if SHADOWS_SCREEN
    float4 clipPos = TransformWorldToHClip(WorldPos);
    shadowCoord = ComputeShadowCoord(clipPos);
    #else
    shadowCoord = TransformWorldToShadowCoord(WorldPos);
    #endif
    mainLight.attenuation = MainLightRealtimeShadowAttenuation(shadowCoord);
    #endif
    Attenuation = mainLight.attenuation;
    }";

    //This string is passed to the node to generate the shader that's used in the ShaderGraph for preview.
    //Since the graph has no conception of what's the main light, we fake the data by hardcoding it in.
    private static string functionBodyPreview = @"{
    Color = 1;
    Direction = float3(-0.5, -.5, 0.5);
    Attenuation = 1;
    }";

    private static bool isPreview;

    //Returns a different string depending on whether we are in the graph or not.
    private static string functionBody
    {
    get
    {
    if(isPreview)
    return functionBodyPreview;
    else
    return functionBodyForReals;
    }
    }

    //Constructor
    public MainLightNode()
    {
    name = "Main Light";
    }

    protected override MethodInfo GetFunctionToConvert()
    {
    return GetType().GetMethod("CustomFunction", BindingFlags.Static | BindingFlags.NonPublic);
    }

    //Will calculate the boolean isPreview which is used to decide which of the 2 strings to use (see above)
    public override void GenerateNodeFunction(FunctionRegistry registry, GraphContext graphContext, GenerationMode generationMode)
    {
    isPreview = generationMode == GenerationMode.Preview;

    base.GenerateNodeFunction(registry, graphContext, generationMode);
    }

    //The definition of the ports. 3 go out, 1 goes in
    //(which also has a default binding of WorldSpacePosition, so it doesn't need to be connected)
    private static string CustomFunction(
    [Slot(0, Binding.None)] out Vector3 Direction,
    [Slot(1, Binding.None)] out Vector1 Attenuation,
    [Slot(2, Binding.None)] out Vector3 Color,
    [Slot(3, Binding.WorldSpacePosition)] Vector3 WorldPos)
    {
    //These default values are needed otherwise Unity will complain that the Vector3s are not initialised.
    //They won't be zero in the shader.
    Direction = Vector3.zero;
    Color = Vector3.zero;

    return functionBody;
    }
    }
  4. @CiroContnsUnity CiroContnsUnity revised this gist Aug 8, 2018. 1 changed file with 13 additions and 2 deletions.
    15 changes: 13 additions & 2 deletions MainLightNode.cs
    Original file line number Diff line number Diff line change
    @@ -9,6 +9,8 @@ public class MainLightNode : CodeFunctionNode
    {
    public override bool hasPreview {get {return false;}}

    //This is the string that's passed into the code of the real, final shader code that is used in the Scene when you hit Apply in the ShaderGraph window.
    //As such, it will use real light data from the Scene (for instance, GetMainLight()).
    private static string functionBodyForReals = @"{
    Light mainLight = GetMainLight();
    Color = mainLight.color;
    @@ -27,7 +29,9 @@ public class MainLightNode : CodeFunctionNode
    Attenuation = mainLight.attenuation;
    }";


    //This string is passed to the node to generate the shader that's used in the ShaderGraph for preview.
    //Since the graph has no conception of what's the main light, we fake the data by hardcoding it in.
    private static string functionBodyPreview = @"{
    Color = 1;
    Direction = float3(-0.5, -.5, 0.5);
    @@ -36,6 +40,7 @@ public class MainLightNode : CodeFunctionNode

    private static bool isPreview;

    //Returns a different string depending on whether we are in the graph or not.
    private static string functionBody
    {
    get
    @@ -47,29 +52,35 @@ private static string functionBody
    }
    }

    //Constructor
    public MainLightNode()
    {
    name = "Main Light";
    }

    protected override MethodInfo GetFunctionToConvert()
    {
    return GetType().GetMethod("CustomFunction", BindingFlags.Static | BindingFlags.NonPublic);
    }

    //Will calculate the boolean isPreview which is used to decide which of the 2 strings to use (see above)
    public override void GenerateNodeFunction(FunctionRegistry registry, GraphContext graphContext, GenerationMode generationMode)
    {
    isPreview = generationMode == GenerationMode.Preview;

    base.GenerateNodeFunction(registry, graphContext, generationMode);
    }

    //The definition of the ports. 3 go out, 1 goes in
    //(which also has a default binding of WorldSpacePosition, so it doesn't need to be connected)
    private static string CustomFunction(
    [Slot(0, Binding.None)] out Vector3 Direction,
    [Slot(1, Binding.None)] out Vector1 Attenuation,
    [Slot(2, Binding.None)] out Vector3 Color,
    [Slot(3, Binding.WorldSpacePosition)] Vector3 WorldPos)
    {
    //These default values are needed otherwise Unity will complain that the Vector3s are not initialised.
    //They won't be zero in the shader.
    Direction = Vector3.zero;
    Color = Vector3.zero;

  5. @CiroContnsUnity CiroContnsUnity created this gist Jul 26, 2018.
    78 changes: 78 additions & 0 deletions MainLightNode.cs
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,78 @@
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEditor.ShaderGraph;
    using System.Reflection;

    [Title("Custom", "Main Light")]
    public class MainLightNode : CodeFunctionNode
    {
    public override bool hasPreview {get {return false;}}

    private static string functionBodyForReals = @"{
    Light mainLight = GetMainLight();
    Color = mainLight.color;
    Direction = mainLight.direction;
    float4 shadowCoord;
    #ifdef _SHADOWS_ENABLED
    #if SHADOWS_SCREEN
    float4 clipPos = TransformWorldToHClip(WorldPos);
    shadowCoord = ComputeShadowCoord(clipPos);
    #else
    shadowCoord = TransformWorldToShadowCoord(WorldPos);
    #endif
    mainLight.attenuation = MainLightRealtimeShadowAttenuation(shadowCoord);
    #endif
    Attenuation = mainLight.attenuation;
    }";

    private static string functionBodyPreview = @"{
    Color = 1;
    Direction = float3(-0.5, -.5, 0.5);
    Attenuation = 1;
    }";

    private static bool isPreview;

    private static string functionBody
    {
    get
    {
    if(isPreview)
    return functionBodyPreview;
    else
    return functionBodyForReals;
    }
    }

    public MainLightNode()
    {
    name = "Main Light";
    }

    protected override MethodInfo GetFunctionToConvert()
    {
    return GetType().GetMethod("CustomFunction", BindingFlags.Static | BindingFlags.NonPublic);
    }

    public override void GenerateNodeFunction(FunctionRegistry registry, GraphContext graphContext, GenerationMode generationMode)
    {
    isPreview = generationMode == GenerationMode.Preview;

    base.GenerateNodeFunction(registry, graphContext, generationMode);
    }

    private static string CustomFunction(
    [Slot(0, Binding.None)] out Vector3 Direction,
    [Slot(1, Binding.None)] out Vector1 Attenuation,
    [Slot(2, Binding.None)] out Vector3 Color,
    [Slot(3, Binding.WorldSpacePosition)] Vector3 WorldPos)
    {
    Direction = Vector3.zero;
    Color = Vector3.zero;

    return functionBody;
    }
    }