思路很简单,我们指定一个裁剪高度_ConstructY,如果模型上某个点的的世界坐标高度大于裁剪高度,就discard(擦除)掉,而裁剪高度到边缘光(白色的扫光)高度之间的点,使用指定颜色渲染。然后我们动态改变_ConstructY,就能实现这个效果。表面着色器代码:
void surf (Input IN, inout SurfaceOutputStandard o) {
//点的世界坐标高度在裁剪高度下,正常渲染
if (IN.worldPos.y < _ConstructY)
{
fixed4 c = tex2D(_MainTex, IN.uv_MainTex) * _Color;
o.Albedo = c.rgb;
o.Alpha = c.a;
building = 0;
}
else
{
//点的世界坐标高度在裁剪高度下,正常渲染
float s = +sin((IN.worldPos.x * IN.worldPos.z) * 240 + _Time[3] + o.Normal) / 120;
o.Albedo = _ConstructColor.rgb;
o.Alpha = _ConstructColor.a;
building = 1;
//扫光之上的像素,擦除掉
if (IN.worldPos.y > _ConstructY + _ConstructGap + s)
{
discard;
}
}
o.Metallic = _Metallic;
o.Smoothness = _Glossiness;
}
接下来,我们要将扫光禁用光照渲染,而正常显示的部分,使用正常的光照渲染,这里通过
building变量来告诉光照模型函数是否正常渲染
inline half4 LightingUnlit(SurfaceOutputStandard s, half3 lightDir, UnityGI gi)
{
if (building)
{
return _ConstructColor; // 不使用光照模型渲染
}
if (dot(s.Normal, lightDir) < 0) //避免出现模型空洞
return _ConstructColor;
return LightingStandard(s, lightDir, gi); // Unity5 PBR
}
inline void LightingUnlit_GI(SurfaceOutputStandard s, UnityGIInput data, inout UnityGI gi)
{
LightingStandard_GI(s, data, gi);
}
此外,我们要将面裁剪关掉,避免出现模型穿破
Cull Off
完整的Shader文件和C#文件:https://pan.baidu.com/s/1bo5CKu7