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

はじめに

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

  • Unity:2018.3.0b9
  • LWRP:4.1.0-preview

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

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

ソースコード

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
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が読み込まれないため固定値を渡すようになっています。

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
[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;
}";
}
}

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

影を受け取る

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

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

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

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

おわりに

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

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