UnityのShader GraphでLWRPのライトの情報を得るカスタムノード

はじめに

現時点でのShader Graphではライトの情報を取得するノードがありません。 ライトの情報を取得するカスタムノードを作成している方がいたので、 そのカスタムノードについて紹介します。

5

  • Unity:2018.3.0b9
  • LWRP:4.1.0-preview

ライトの情報を扱うカスタムノード

こちらがライトの情報を扱うカスタムノードです。

ソースコード

何をやっているのか確認するために メインライトの情報を取得するノードのソースコードを見てみます。

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

[Title("Custom", "Main Light")]
public class MainLightNode : CodeFunctionNode
{
    public MainLightNode()
    {
        name = "Main Light";
    }
    protected override MethodInfo GetFunctionToConvert()
    {
        return GetType().GetMethod("MainLightNodeFunction",
            BindingFlags.Static | BindingFlags.NonPublic);
    }
    public static bool isPreview;
    public override void GenerateNodeFunction(FunctionRegistry registry, GraphContext graphContext, GenerationMode generationMode)
    {
        isPreview = generationMode == GenerationMode.Preview;

        base.GenerateNodeFunction(registry, graphContext, generationMode);
    }
    static string MainLightNodeFunction(
    [Slot(0, Binding.WorldSpacePosition)] Vector3 WorldPos,
    [Slot(1, Binding.ObjectSpacePosition)] Vector3 ObjPos,
    [Slot(2, Binding.None)] out Vector3 Direction,
    [Slot(3, Binding.None)] out Vector3 Color,
    [Slot(4, Binding.None)] out Vector1 DistanceAttenuation,
    [Slot(5, Binding.None)] out Vector1 ShadowAttenuation
    )
    {
        Direction = Vector3.zero;
        Color = Vector3.one;
        DistanceAttenuation = new Vector1();
        ShadowAttenuation = new Vector1();
        if (!isPreview)
        {
            return Shader;
        }
        else
        {
            return PreviewShader;
        }
    }
    public static string Shader = @"{
        Light light = GetMainLight(GetShadowCoord(GetVertexPositionInputs(ObjPos)));
        Direction = light.direction;
        DistanceAttenuation = light.distanceAttenuation;
        Color = light.color;
        ShadowAttenuation = light.shadowAttenuation;
    }";
    public static string PreviewShader = @"{
        Direction = float3(-0.5, 0.5, -0.5);
        Color = float3(1, 1, 1);
        DistanceAttenuation = 0.4;
        ShadowAttenuation = 0.4;
    }";
}

プレビューではLWRPのLighting.hlslが読み込まれないため固定値を渡すようになっています。

次のようにプレビューを考慮しないノードを作るとエラーになります。

[Title("Custom", "Main Light")]
public class MainLightNode : CodeFunctionNode
{
    public MainLightNode()
    {
        name = "Main Light";
    }
    protected override MethodInfo GetFunctionToConvert()
    {
        return GetType().GetMethod("MainLightNodeFunction",
            BindingFlags.Static | BindingFlags.NonPublic);
    }
    static string MainLightNodeFunction(
    [Slot(0, Binding.WorldSpacePosition)] Vector3 WorldPos,
    [Slot(1, Binding.ObjectSpacePosition)] Vector3 ObjPos,
    [Slot(2, Binding.None)] out Vector3 Direction,
    [Slot(3, Binding.None)] out Vector3 Color,
    [Slot(4, Binding.None)] out Vector1 DistanceAttenuation,
    [Slot(5, Binding.None)] out Vector1 ShadowAttenuation
    )
    {
        Direction = Vector3.zero;
        Color = Vector3.one;
        DistanceAttenuation = new Vector1();
        ShadowAttenuation = new Vector1();
        return @"{
    Light light = GetMainLight(GetShadowCoord(GetVertexPositionInputs(ObjPos)));
    Direction = light.direction;
    DistanceAttenuation = light.distanceAttenuation;
    Color = light.color;
    ShadowAttenuation = light.shadowAttenuation;
}";
    }
}

0

プレビューではLWRPのLighting.hlslが読み込まれず、 Light構造体が定義されないためエラーになっています。

影を受け取る

UnlitのMasterノードにつなぐと影を受け取れません。

1

UnlitのMasterノードでは_MAIN_LIGHT_SHADOWSキーワードの 設定されないことが原因のようです。 LWRPのShadows.hlsl内部で_MAIN_LIGHT_SHADOWSが存在しない場合は 常に1を返すコードになっていました。

2

3

サンプルシーンではPBRのMasterのEmissionにノードをつなぐことでごまかしているようでした。

4

5

きちんとやるならば_MAIN_LIGHT_SHADOWSキーワードを与える Masterノードを作成することになるのでしょうか。 MasterノードのソースコードもGitHubにあるので読むことができます。 軽く読んでみましたがなかなか面倒そうです。

おわりに

ライトの情報を取得するノードの紹介でした。

そのうち公式からもライトの情報を扱うノードが来てくれても良さそうな気がします。

新しい投稿