UnityのShader GraphでLWRPのライトの情報を得るカスタムノード
はじめに
現時点でのShader Graphではライトの情報を取得するノードがありません。 ライトの情報を取得するカスタムノードを作成している方がいたので、 そのカスタムノードについて紹介します。
- 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;
}";
}
}
プレビューでは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にあるので読むことができます。
軽く読んでみましたがなかなか面倒そうです。
おわりに
ライトの情報を取得するノードの紹介でした。
そのうち公式からもライトの情報を扱うノードが来てくれても良さそうな気がします。