仕事上の需要で、キャラクターやオブジェクトの影だけが落ちて、それ以外は描画されないようなshaderが必要になりインターネットの海で見つけたのが以下の記事。
https://qiita.com/kochiyukimoto/items/a687531ab94d21aa0801
DirectionalLightの影を落とすだけなら以下の画像のような効果がつくれます
ただ、spotLightなどいわゆる追加ライトの影が落ちないようになっていため、現状のURPでの
対応を含めShaderGraph対応をしてみました。
結論
コードだけ知りたい方はここだけ見れば大丈夫です。
変更点はGetAdditionalLight
で引数が1つ増えてます。
//既存のコードはこれ
Light AddLight0 = GetAdditionalLight(i.worldPos);
//新規がこれ
Light AddLight0 = GetAdditionalLight(i, worldPos,1);
これだけで追加ライトの対応は完了です。 とりあえず1にしておけば動くが、なぜ1でよいのかは調べ中。
追記(2024/09/01)
最後の引数はshadowMaskというプロパティで、どうにも渡す値によらずこのプロパティがある方でのみライトの影減衰率を渡しており、これが影響している模様。
ShaderGraph対応
カスタムノード化したコードがこちら。
#ifndef YOTHUBALAB_RECEIVESHAODW_INCLUDED
#define YOTHUBALAB_RECEIVESHADOW_INCLUDED
#ifndef SHADERGRAPH_PREVIEW
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
#endif
#pragma multi_compile _ _MAIN_LIGHT_SHADOWS
#pragma multi_compile _ _MAIN_LIGHT_SHADOWS_CASCADE
#pragma multi_compile _ _ADDITIONAL_LIGHT_SHADOWS
#pragma multi_compile _ _SHADOWS_SOFT
void ReceiveShadow_half(float shadowAlpha,float3 worldPos, out half shadowAttenuation)
{
#ifdef SHADERGRAPH_PREVIEW
shadowAttenuation = 1.0;
#else
half4 shadowCoord = TransformWorldToShadowCoord(worldPos);
Light mainLight = GetMainLight(shadowCoord);
half shadow = mainLight.shadowAttenuation;
int pixelLightCount = GetAdditionalLightsCount();
for(int i = 0; i < pixelLightCount; i++)
{
Light AddLight0 = GetAdditionalLight(i, worldPos,1);
half shadow0 = AddLight0.shadowAttenuation;
shadow *= shadow0;
}
shadowAttenuation = shadow * shadowAlpha;
#endif
}
#endif
カスタムノード自体の詳細は省きますが、ifdef SHADERGRAPH_PREVIEW
で分岐している箇所だけ説明するとShaderGraphのエディタ上で表示されるpreviewの描画でライト周りの関数にアクセスできないため、分岐で処理を分けています。
参考 https://blog.unity.com/ja/engine-platform/custom-lighting-in-shader-graph-expanding-your-graphs-in-2019
使用例
CustomNode化したコードをさらにサブグラフ化してしようしております。(GetShadow)
サブグラフの出力であるShadowAttenuationは影部分で0,そうでない部分で1になるような数値ですので、
OneMinus
してあげることで、影部分では1、そうでない部分では0となるようにします。
それをアルファに入力してあげることで、影部分以外を描画しないようなMaterialを作成できます。