如何在unity的URP下实现阴影

2022-08-03 11:56:42

如果你之前是用buildin pipeline写的shader,其中用了SHADOW_ATTENUATION宏的话,在URP下会失效。

由于官方文档对自定义shader描述不多,所以自己只能去看URP内建的shader源码去看实现方法。

但是URP内建的shader都是用HLSLPROGRAM和ENDHLSL来写的,并且引用文件都是.hlsl。

和之前的CGPROGRAM,还有引用文件类型.cginc有所不同。

所以,如果想引用URP内建的方法和接口,必须得按照它们现在的方式来写。

但经师傅指点,我看到了Unity官方的这一段话:

原来我们一直都是用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):

但物体上自己没有阴影,是因为原来的SHADOW_ATTENUATION失效了。

在URP的源代码的upgrade-guide-7-2-0.md文档里,有提到这么一段话:

我翻译一下,就是如果有自定义的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

好,物体上的阴影也出现了。效果可以当然可以再调整下,毕竟

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.unity.render-pipelines.universal@7.3/manual/upgrade-lwrp-to-urp.html

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

  • 作者:黄琅
  • 原文链接:https://blog.csdn.net/zakerhero/article/details/106274331
    更新时间:2022-08-03 11:56:42