闲谈
相信大家在日常工作中发现了一个问题 , urp下虽然可以做到3个Pass 去写我们想要的效果,但是,不能合批(不能合批,那不是我们CPU要干冒烟~!)
好家伙,熊猫老师的偏方来了 ,教大家如何在URP渲染管线下做到多pass也能合批,干货满满。
一:合并公共预设
方便我们多Pass状态下 ,更快的实现,也能让代码更加专业。
如图所示:
我们在Subshader下用 HLSLINCLUDE 和 ENDHLSL 去实现。
其次 咱们在第二个Pass "影子渲染pass"里面添加Tags 并对LightMode 复制渲染层为 "XiongMaoWuDao"
如图所示:
Pass
{
Name "XiongMaoWuDao"
Tags{
"LightMode" = "XiongMaoWuDao"
}
二:URP Add Renderer Feature
如图步骤:
添加Renderer Feature 设置如下:
好了,现在我们来看看多物件下影子Pass是否合批。
上才艺:
Shader "XiongMaoWuDao/Shadow"
{
Properties
{
[MainColor] _BaseColor("BaseColor", Color) = (1,1,1,1)
[MainTexture] _BaseMap("BaseMap", 2D) = "white" {}
//影子处理
//影子淡出处理
_ShadowColor("Color", Color) = (0, 0, 0, 1)
_LightDir ("Light Direction", Vector) = (0, 1, 0, 0)
_PlaneY ("Plane Height", Float) = 0
_ShadowFalloff ("ShadowFalloff ",Range (0,1)) = 0.5
}
SubShader
{
Tags { "RenderType" = "Opaque" "RenderPipeline" = "UniversalPipeline" "Queue" = "Opaque"}
HLSLINCLUDE
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
TEXTURE2D(_BaseMap);
SAMPLER(sampler_BaseMap);
CBUFFER_START(UnityPerMaterial)
float4 _BaseMap_ST;
half4 _BaseColor;
float4 _ShadowColor;
half3 _LightDir;
half _PlaneY;
half _ShadowFalloff;
CBUFFER_END
ENDHLSL
pass
{
Name "Forward"
Tags {
}
HLSLPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_instancing
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
UNITY_VERTEX_INPUT_INSTANCE_ID
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
UNITY_VERTEX_INPUT_INSTANCE_ID
};
v2f vert (appdata v)
{
v2f o;
UNITY_SETUP_INSTANCE_ID(v);
UNITY_TRANSFER_INSTANCE_ID(v, o);
o.vertex = TransformObjectToHClip(v.vertex.xyz);;
o.uv = TRANSFORM_TEX(v.uv, _BaseMap);
return o;
}
half4 frag (v2f i) : SV_Target
{
UNITY_SETUP_INSTANCE_ID(i);
return SAMPLE_TEXTURE2D(_BaseMap, sampler_BaseMap, i.uv) * _BaseColor;
}
ENDHLSL
}
Pass
{
Name "XiongMaoWuDao"
Tags{
"LightMode" = "XiongMaoWuDao"
}
//添加模板缓冲区是解决影子重叠问题(降低透明度就能发现)
Stencil
{
Ref 1 //和模板缓冲区的值进行比较。
Comp NotEqual //比较函数, 决定参考值和模板缓冲区的值如何比较 (是否相等) NotEqual
Pass Replace //模板测试通过时候的操作 。 Replace 模板缓冲区中的值设为参考值。Replace
Fail Keep //模板测试失败时候的操作 。 keep是保持缓冲区当前的值
//ZFail Keep
}
Blend SrcAlpha OneMinusSrcAlpha
// ZWrite off
// Offset -1 , 0
HLSLPROGRAM
#pragma vertex vert
#pragma fragment frag
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
float4 color : COLOR;
};
//阴影方向计算。
float3 PlanarShadowPos(float3 posWS)
{
float3 L = normalize(_LightDir);
float3 N = float3(0, 1, 0);
float d1 = dot(L, N);
float d2 = posWS.y - _PlaneY;
// 阴影坐标沿法线方向偏移一点,防止与平面重叠时出现z-fighting的问题
float3 offsetByNormal = N * 0.001;
return posWS - L * (d2 / d1) + offsetByNormal;
}
v2f vert (appdata v)
{
v2f o;
// 顶点坐标,转世界坐标
float3 posWS = TransformObjectToWorld(v.vertex.xyz);
// 世界顶点坐标转为平面坐标
posWS = PlanarShadowPos(posWS);
o.vertex = TransformWorldToHClip(posWS);
o.uv =v.uv;
//得到中心点世界坐标
float3 center = float3(unity_ObjectToWorld[0].w, _PlaneY, unity_ObjectToWorld[2].w);
//计算阴影衰减
float falloff = 1 - saturate(distance(posWS, center) * _ShadowFalloff);
o.color = _ShadowColor;
o.color.a *=falloff;
return o;
}
half4 frag (v2f i) : SV_Target
{
return i.color;
}
ENDHLSL
}
}}
能看见我在场景中做了4个材质球且用了不同的贴图,但是 能看见第一个pass对颜色渲染已经合批成一个了(除了地面用了默认的材质球外,忽略)。 第二个Pass影子也全部合并成一个渲染层渲染,完美解决问题。 鼓掌~~~!