天天看點

如何在unity的URP下實作陰影

如果你之前是用buildin pipeline寫的shader,其中用了SHADOW_ATTENUATION宏的話,在URP下會失效。

由于官方文檔對自定義shader描述不多,是以自己隻能去看URP内建的shader源碼去看實作方法。

但是URP内建的shader都是用HLSLPROGRAM和ENDHLSL來寫的,并且引用檔案都是.hlsl。

和之前的CGPROGRAM,還有引用檔案類型.cginc有所不同。

是以,如果想引用URP内建的方法和接口,必須得按照它們現在的方式來寫。

但經師傅指點,我看到了Unity官方的這一段話:

如何在unity的URP下實作陰影

原來我們一直都是用HLSL來寫的shader,并非是cg語言,隻是keywords和檔案引用沒改成HLSL方式的。

是以我們要直接改成HLSL方式的shader還是比較友好的。

具體的操作方法是:

首先把我們的CGPROGRAM、ENDCG分别改成HLSLPROGRAM和ENDHLSL。

接着把#include "UnityCG.cginc"等檔案引用改成

#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"這種方式,

具體要引用哪些檔案,要自己去

Editor\Data\Resources\PackageManager\Editor\com.unity.render-pipelines.universal-7.3.1

目錄下,解壓包,看具體想引用哪個檔案,再把相對路徑寫上去。

上面隻是把cg的方式改成HLSL的方式,下面是具體實作urp的陰影方法:

首先,我看到了這一篇文章:

關于SHADOWS_SCREEN

要寫入 ShadowMap,shader必須有 ShadowCaster 這個Pass。

2021年1月28日更新:

加入下面這句代碼即可。使用URP自帶的ShadowCaster。

UsePass "Universal Render Pipeline/Lit/ShadowCaster"

或者

是以我在shader裡加入了這一個pass:

pass {
			Tags{ "LightMode" = "ShadowCaster" }
			HLSLPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"

			struct appdata
			{
				float4 vertex : POSITION;
			};

			struct v2f
			{
				float4 pos : SV_POSITION;
			};

			sampler2D _MainTex;
			float4 _MainTex_ST;

			v2f vert(appdata v)
			{
				v2f o;
				o.pos = mul(UNITY_MATRIX_MVP,v.vertex);
				return o;
			}
			float4 frag(v2f i) : SV_Target
			{
				float4 color;
				color.xyz = float3(0.0, 0.0, 0.0);
				return color;
			}
			ENDHLSL
		}
           

确實地面的投影就出現了(地面的shader是URP内建的Lit):

如何在unity的URP下實作陰影

但物體上自己沒有陰影,是因為原來的SHADOW_ATTENUATION失效了。

在URP的源代碼的upgrade-guide-7-2-0.md文檔裡,有提到這麼一段話:

如何在unity的URP下實作陰影

我翻譯一下,就是如果有自定義的shader,想去采樣Shadermap貼圖,可以用舉例的方法:

float4 SHADOW_COORDS = TransformWorldToShadowCoord(i.worldPos);
Light mainLight = GetMainLight(SHADOW_COORDS);
half shadow = mainLight.shadowAttenuation;
           

要讓以上方法生效,必須定義以下的宏:

#pragma multi_compile _ _MAIN_LIGHT_SHADOWS
#pragma multi_compile _ _MAIN_LIGHT_SHADOWS_CASCADE
           
如何在unity的URP下實作陰影

好,物體上的陰影也出現了。效果可以當然可以再調整下,畢竟

half shadow = mainLight.shadowAttenuation;隻是個0-1的值,表現還是自己想辦法去做過渡之類的。

但是有個問題,這個陰影有鋸齒。具體如何解決呢,歡迎大家讨論。我也會想辦法解決。

代碼例子如下:

Shader "Custom/ToonGroundExam"
{
	Properties
	{
		_MainTex("主貼圖", 2D) = "white" {}
	}
		SubShader
		{
		Tags { "RenderType" = "Transparent" "Queue" = "Transparent" }
		Pass
		{
			Blend SrcAlpha OneMinusSrcAlpha
			Tags
			{
				"LightMode" = "UniversalForward"
			}
			Zwrite off
			HLSLPROGRAM
			#pragma vertex vert
			#pragma fragment frag

			#pragma multi_compile _ _MAIN_LIGHT_SHADOWS
			#pragma multi_compile _ _MAIN_LIGHT_SHADOWS_CASCADE
			#pragma multi_compile _ Anti_Aliasing_ON

			#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
			#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"

			struct appdata
			{
				float4 vertex : POSITION;
				float4 uv : TEXCOORD0;

			};

			struct v2f
			{
				float4 pos : SV_POSITION;
				float2 uv : TEXCOORD0;
				float3 worldPos : TEXCOORD1;
			};

			sampler2D _MainTex;
			float4 _MainTex_ST;

			v2f vert(appdata v)
			{
				v2f o;
				o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
				o.worldPos = mul(unity_ObjectToWorld, v.vertex);
				o.uv = TRANSFORM_TEX(v.uv, _MainTex);

				return o;
			}

			float4 _Color;

			float4 frag(v2f i) : SV_Target
			{
				float4 SHADOW_COORDS = TransformWorldToShadowCoord(i.worldPos);

				Light mainLight = GetMainLight(SHADOW_COORDS);
				half shadow = MainLightRealtimeShadow(SHADOW_COORDS);

				return float4(shadow, shadow, shadow,1);
			}
			ENDHLSL
		}
		pass {
			Name "ShadowCast"

			Tags{ "LightMode" = "ShadowCaster" }
			HLSLPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"

				struct appdata
			{
				float4 vertex : POSITION;
			};

			struct v2f
			{
				float4 pos : SV_POSITION;
			};

			sampler2D _MainTex;
			float4 _MainTex_ST;

			v2f vert(appdata v)
			{
				v2f o;
				o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
				return o;
			}
			float4 frag(v2f i) : SV_Target
			{
				float4 color;
				color.xyz = float3(0.0, 0.0, 0.0);
				return color;
			}
			ENDHLSL
		}
	}
}
           

參考網址:

https://docs.unity3d.com/Packages/com.unit[email protected]/manual/upgrade-lwrp-to-urp.html

https://baddogzz.github.io/2019/12/19/URP-Shadow/