Пример использования шейдера для отображения тени в встроенном Render Pipeline
Наш шейдер в настоящее время не может ни получать, ни бросать тени. Давайте сначала реализуем бросание теней.
Чтобы отбрасывать тени, шейдер должен содержать ShadowCaster, то есть проход типа, в любом из своих подшейдеров или в любом запасном варианте. Проход ShadowCaster используется для рендеринга объекта в карту теней и обычно довольно прост: вершинному шейдеру достаточно вычислить положение вершины, а фрагментный шейдер практически ничего не делает. Карта теней представляет собой только буфер глубины, поэтому даже цвет, выводимый фрагментным шейдером, фактически не имеет значения.
Это означает, что для большинства шейдеров проход shadow caster будет почти точно таким же (если только объект не имеет собственных деформаций, основанных на вершинном шейдере, или имеет альфа-вырезку / полупрозрачные части). Самый простой способ втянуть его — через UsePass shader команду:
Pass
{
// regular lighting pass
}
// pull in shadow caster from VertexLit built-in shader
UsePass "Legacy Shaders/VertexLit/SHADOWCASTER"
Однако мы здесь учимся, так что давайте сделаем то же самое “вручную”, так сказать. Для более короткого кода, мы заменили проход освещения (“ForwardBase”) кодом, который делает только нетекстурированную окружающую среду. Под ним, есть проход “ShadowCaster”, который делает объект поддержки теней.
Shader "Lit/Shadow Casting"
{
SubShader
{
// very simple lighting pass, that only does non-textured ambient
Pass
{
Tags {"LightMode"="ForwardBase"}
HLSLPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct v2f
{
fixed4 diff : COLOR0;
float4 vertex : SV_POSITION;
};
v2f vert (appdata_base v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
half3 worldNormal = UnityObjectToWorldNormal(v.normal);
// only evaluate ambient
o.diff.rgb = ShadeSH9(half4(worldNormal,1));
o.diff.a = 1;
return o;
}
fixed4 frag (v2f i) : SV_Target
{
return i.diff;
}
ENDHLSL
}
// shadow caster rendering pass, implemented manually
// using macros from UnityCG.cginc
Pass
{
Tags {"LightMode"="ShadowCaster"}
HLSLPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_shadowcaster
#include "UnityCG.cginc"
struct v2f {
V2F_SHADOW_CASTER;
};
v2f vert(appdata_base v)
{
v2f o;
TRANSFER_SHADOW_CASTER_NORMALOFFSET(o)
return o;
}
float4 frag(v2f i) : SV_Target
{
SHADOW_CASTER_FRAGMENT(i)
}
ENDHLSL
}
}
}
Теперь под ним есть плоскость, использующая обычный встроенный Diffuse shader, так что мы можем увидеть, как работают наши тени (помните, наш текущий shader не поддерживает , получающий тени пока!).
Мы использовали директиву #pragma multi_compile_shadowcaster. Это приводит к тому, что шейдер компилируется в несколько вариантов с различными макросами препроцессора, определенными для каждого (см. несколько вариантов шейдера page для подробностей). При рендеринге в shadowmap, случаи точечных светов по сравнению с другими типами света требуют слегка отличного кода шейдера, поэтому эта директива нужна.