UnityのShader GraphでLWRPのライトの情報を得るカスタムノード
はじめに
現時点でのShader Graphではライトの情報を取得するノードがありません。 ライトの情報を取得するカスタムノードを作成している方がいたので、 そのカスタムノードについて紹介します。
- Unity:2018.3.0b9
- LWRP:4.1.0-preview
ライトの情報を扱うカスタムノード
Made some custom nodes for Unity's Shader Graph that exposes light information. Indispensable for creating custom lighting behaviours. It has Lambert and Specular nodes as well as multiple lights support.https://t.co/iOQuskUTW2#gamedev #unity3d #unitytips pic.twitter.com/w9AkCTydQv
— Paulo Patez (@paulopatez) 2018年11月9日
こちらがライトの情報を扱うカスタムノードです。
ソースコード
何をやっているのか確認するために メインライトの情報を取得するノードのソースコードを見てみます。
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にあるので読むことができます。
軽く読んでみましたがなかなか面倒そうです。
おわりに
ライトの情報を取得するノードの紹介でした。
そのうち公式からもライトの情報を扱うノードが来てくれても良さそうな気がします。