Wait a moment...

Unity2019.3 URP ShaderGraph Unlit マスターで影を受ける

36759
mizinco
nem1.70xem (2)
1485
2
2019-12-25 15:14:22
Unity2019.3 URP ShaderGraph Unlit マスターで影を受ける

こんにちは、今回はUnityのシェーダーの解説記事です。

 

いつか誰かがこの記事を読んでくれた時に助けになれば幸いです。

 

 

UnityにはShaderGraphというものがあります。

これはプログラミングなしで、描画の仕方を決めれるところに利点があります。

また、Unityの仕様変更でシェーダーをいちいち書き直さなくていいメリットがある(かもしれません)

 

 

今回は、処理の超絶軽いUnlitマスターノードに、

ライトの情報を得るカスタムファンクションを作り、影の投影とシェーディングを行い、

さらに、強引に影を受けるところまで進めます。

影を受けるのが結構苦労しました。

 

ライトの情報を得るカスタムファンクションは公式にも紹介があります。

https://blogs.unity3d.com/jp/2019/07/31/custom-lighting-in-shader-graph-expanding-your-graphs-in-2019/

基本的にはこの情報だけで、ライトの情報を受け、シェーディングと影の投影はできるので、

割愛させていただきます。

https://github.com/Unity-Technologies/ShaderGraph-Custom-Lighting

ここのAssets/Includes/CustumLighting.HLSLを使うだけです。

 

このスクリプト内に影の強さ、ShadowAttenがあるのですが値は返ってきません

 

本来、影を受けるためには、

multi_compile _MAIN_LIGHT_SHADOWS

shader_feature _RECEIVE_SHADOWS_OFF

 

このあたりをシェーダー内で記述すると、本来は影の強さ、

CustumLighting.HLSLのShadowAttenが返ってくる…はずなんです。

 

しかしShaderGraph内に、

multi_compile _MAIN_LIGHT_SHADOWS

これを記載すると、ShaderGraphのVerifyings.hlslの最後、

#ifdef _MAIN_LIGHT_SHADOWS
    output.shadowCoord = GetShadowCoord(vertexInput);
#endif

    return output;

ここでエラーが出てしまいます。

 

そこでmulti_compile _MAIN_LIGHT_SHADOWSを使用せずに、

影を受けるメソッドを探し、記載することにしました。

要は、_MAIN_LIGHT_SHADOWSの定義で分岐するところ分岐先を強引につなげて、影を得ていきます。

 

まずは、元のCustumLighting.HLSLの影の強さ

ShadowAtten = mainLight.shadowAttenuation;

 

これはLighting.hlsl内のこの部分のことですね。

Light GetMainLight(float4 shadowCoord)
{
    Light light = GetMainLight();
    light.shadowAttenuation = MainLightRealtimeShadow(shadowCoord);
    return light;
}

次にMainLightRealtimeShadow(shadowCoord)を探します。

これはShadow.hlsl内にあります。

half MainLightRealtimeShadow(float4 shadowCoord)
{
#if !defined(_MAIN_LIGHT_SHADOWS) || defined(_RECEIVE_SHADOWS_OFF)
    return 1.0h;
#endif

#if SHADOWS_SCREEN
    return SampleScreenSpaceShadowmap(shadowCoord);
#else
    ShadowSamplingData shadowSamplingData = GetMainLightShadowSamplingData();
    half4 shadowParams = GetMainLightShadowParams();
    return SampleShadowmap(TEXTURE2D_ARGS(_MainLightShadowmapTexture, sampler_MainLightShadowmapTexture), shadowCoord, shadowSamplingData, shadowParams, false);
#endif
}

はい、きました。

multi_compile _MAIN_LIGHT_SHADOWS

shader_feature _RECEIVE_SHADOWS_OFF の分岐。

Unlitマスターではこれらの定義がされていないので、返り値は1.0hの部分になります。

なので、いつまでたっても影の強さは1.0(1は白、0が影です)

 

これを分岐先を強引に取り出します。

下から3行があればいいですね。

 

SampleShadowmap(~~~)この中のshadowCoordだけは値を作らなければなりません。

shadowCoordの取得先もShadow.hlslの中にあります。

float4 GetShadowCoord(VertexPositionInputs vertexInput)
{
#if SHADOWS_SCREEN
    return ComputeScreenPos(vertexInput.positionCS);
#else
    return TransformWorldToShadowCoord(vertexInput.positionWS);
#endif
}

ここで出てきたVertexPositionInputsとは…先ほどお話ししたエラー先Verifyings.hlslにあるのですが、

要はpositionWS…ワールドスペースのポジションでOKです。

 

 

これらをまとめて、CustomLighting.hlslに記載してしまえばいいのです。

こちらが元のコード

void MainLight_float(float3 WorldPos, out float3 Direction, out float3 Color, out float DistanceAtten, out float ShadowAtten)
{
#if SHADERGRAPH_PREVIEW
	Direction = float3(0.5, 0.5, 0);
	Color = 1;
	DistanceAtten = 1;
	ShadowAtten = 1;
#else
#if SHADOWS_SCREEN
	float4 clipPos = TransformWorldToHClip(WorldPos);
	float4 shadowCoord = ComputeScreenPos(clipPos);
#else
	float4 shadowCoord = TransformWorldToShadowCoord(WorldPos);
#endif
	Light mainLight = GetMainLight(shadowCoord);
	Direction = mainLight.direction;
	Color = mainLight.color;
	DistanceAtten = mainLight.distanceAttenuation;
	ShadowAtten = mainLight.shadowAttenuation;
#endif
}

これの下の部分のLight~ShadowAttenをこう書き換えます。

Light mainLight = GetMainLight();
	Direction = mainLight.direction;
	Color = mainLight.color;
	DistanceAtten = mainLight.distanceAttenuation;
	ShadowSamplingData shadowSamplingData = GetMainLightShadowSamplingData();
	half4 shadowParams = GetMainLightShadowParams();
	ShadowAtten = SampleShadowmap(TEXTURE2D_ARGS(_MainLightShadowmapTexture, sampler_MainLightShadowmapTexture), TransformWorldToShadowCoord(WorldPos), shadowSamplingData, shadowParams, false);

GetMainLight()で、DirevtionやColorは取得できます。

ShadowAtten周りだけ書き換えて、強引にシーン上の影を取得することができます。

 

 

右のスフィアが黒い箱の影を受けれるようになりました。

 

 

 

いやーネットを探してもなかなかこんなことしてる人いないみたい。

Unityの公式デモでは、PBRマスターのエミッションに描きこんで強引にトゥーン調を再現する方法があったかなぁ

 

本日はこれまで!

シェーダーを完成させたら販売モデルのシェーダー更新予定ですー

Comment
mizinco
mizinco
2019-12-26 09:10:25ID:165995

>>matsuno.::さん
それ目指してます!
クローズドβ的なのはnemlog内で行う予定です~
(サーバーの関係で接続人数が少ないためw)

matsuno
matsuno
2019-12-26 00:45:33ID:165980

すごー
将来、mizincoさんのVRMアバター使ってNEMLOG座談会とかやれたら面白いね!

この記事を書いた人
blenderで3Dモデルを作ったりして遊んでます。 nem決済でオリジナル3Dアバターを作成します! 詳細はまだ決めていない… 気になる方は是非お声掛けくださいませ。