之前在一个搭建户型的APP上看到这样的一个效果:拉出一面墙,然后再往墙上加一个窗户,透过窗户可以看到外面的景物,并且还可以随意移动窗户的位置。
类似的效果虽然可以通过动态布尔运算对模型进行实时“扣洞”,但是由于计算量太大,所以这不是一个很好的解决方案。
所以这种效果还是交给shader来解决吧,本次讲解的就是这种穿透效果。开始之前先看一下最终的效果:

最终效果
1.窗户上的玻璃优先绘制,在绘制的同时,会在Stencil Buffer里玻璃的部分写入一个参照数值1
2.然后绘制墙壁,墙壁在绘制的时候也会提供一个参照值1,然后去Stencil Buffer里跟玻璃部分的参照值进行对比
3.我们把Stencil Buffer里墙壁参考值跟玻璃不相等的部分绘制出来,把相等的部分放弃绘制,从而实现镂空效果
Shader "Custom/Glass"{
SubShader
{
Tags { "Queue" = "Geometry-1" }
//一下为主要部分 Stencil
{
Ref 1
Comp Always
Pass Replace
}
//以上为主要部分
ColorMask 0
ZWrite Off
CGPROGRAM
#pragma surface surf Standard
sampler2D _MainTex;
struct Input
{
float2 uv_MainTex;
};
void surf (Input IN, inout SurfaceOutputStandard o)
{
o.Albedo = tex2D(_MainTex, IN.uv_MainTex).rgb;
}
ENDCG
}
FallBack "Diffuse"}
1.渲染队列为Geometry-1是为了比墙壁优先渲染
2.参照数值为1,且总是让玻璃通过Stencil测试,然后把参照数值写进Stencil Buffer里
3.因为我们想要窗户完全穿透过去,所以把ColorMask设置为0,不进行任何渲染
4.关闭深度写入,防止挡住后边的物体
Shader "Custom/Wall"{
Properties
{
_Color ("Color", Color) = (1,1,1,1)
_MainTex ("Albedo (RGB)", 2D) = "white" {}
}
SubShader
{
Tags { "Queue"="Geometry" }
//以下为主要部分 Stencil
{
Ref 1
Comp NotEqual
Pass Keep
}
//以上为主要部分
CGPROGRAM
#pragma surface surf Standard fullforwardshadows
sampler2D _MainTex;
struct Input
{
float2 uv_MainTex;
};
fixed4 _Color;
void surf (Input IN, inout SurfaceOutputStandard o)
{
fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
o.Albedo = c.rgb;
}
ENDCG
}
FallBack "Diffuse"}
1.渲染队列为正常的Geometry
2.参照数值为1,跟写进Stencil Buffer里的玻璃参照数值做对比,之后不相等的部分才能通过Stencil测试
3.通过测试之后继续保持Buffer里的内容
遗憾的是,我还没有想到让灯光射进窗户的方法。如果各位有好的方法,请告诉我。