思路很简单,我们指定一个裁剪高度_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