这篇主要写一下关于各种溶解算法的使用,以及消解算法延伸出来的材质过度,还有在 Unity 中用 C# 脚本控制消解的简单框架。
最基本的简单溶解
所谓的溶解都可以被分成三个部分:
未溶解的部分:完全不透明,保持原有固有色。
已溶解的部分:完全透明,不可见。
溶解边缘:溶解部分的边界,可能会发光、可能不平整。
因此,最基本的溶解效果我们就遵循这个思路。
算法概括
采样渐变图。用一个 Property 去控制实际的黑白区域,用 step 确定未溶解和已溶解的部分。
确认边缘区域。离溶解边缘近的区域的边缘判定值为 1。
越接近边缘,颜色越靠近边缘的颜色;否则,则靠近采样的固有色。
步骤一 采样渐变图,将渐变图的 r 通道作为材质的 alpha 通道。为了做出向上溶解的效果,我们让它去减去一个变量数值 _ChangeAmount;由于我们的 AlphaGreaterThan 默认设置成 0.5,所以我们将_ChangeAmount 的范围设置为 [-1, 1];
这里,所谓的渐变图就是下黑上白渐变的一张图。如下:
渐变图
fixed4 frag (v2f i) : SV_Target
{
// 采样渐变图。
float grad = tex2D(_Gradient, i.uv).r - _ChangeAmount;
fixed4 col = tex2D(_MainTex, i.uv);
// 将透明通道设置成 grad 采样出来的结果,但是要给一条尽可能明确一点的边缘。
col.a = step(0.5, grad);
return col;
}
步骤二 识别边缘区域。
在上面,我们通过 step(0.5, grad) 设置了片元的可见性。step 是二值的,所以要么可见要么不可见。在这里,只有 grad 大于等于 0.5 时,col.a 才会被设置为 1。所以,0.5 相当于是边缘所在的“位置”。
与 0.5 的值差距在一定值的范围内时,它就可以被认为是边缘,否则就会被当做非边缘处理。显然,我们需要一个 edge 变量来处理。另外,差距越小越应该在边缘上,所以应该要有一个 OneMinus 的操作。
我们可以通过再让 abs(grad - 0.5) 再去除以一个 _EdgeWidth;这样的话 _EdgeWidth 越大,abs(grad - 0.5) 得到的值就越小,1 - abs(grad - 0.5) /_EdgeWidth 得到的值也就越大,符合 _EdgeWidth 越大,边缘范围越大的特征。
最后,我们再将原采样 _MainTex 得到的 col.rgb 进行修改,使其越接近边缘则颜色越接近 _EdgeColor 设定的颜色,用 lerp 则可以轻松做到。也可以再加一个 _EdgeIntensity 控制这个边缘光的强度。
fixed4 frag (v2f i) : SV_Target
{
// 采样渐变图。
float grad = tex2D(_Gradient, i.uv).r - _ChangeAmount;
fixed4 col = tex2D(_MainTex, i.uv);
// 将透明通道设置成 grad 采样出来的结果,但是要给一条尽可能明确一点的边缘。
col.a = step(0.5, grad);
// 确定边缘区域
float edge = clamp(1- abs(grad - 0.5)/_EdgeWidth, 0, 1);
// 越靠近边缘的部分越接近边缘的颜色,否则则是原来的颜色,用 lerp
col.rgb = lerp(col.rgb, _EdgeColor.rgb * _EdgeIntensity, edge);
return col;
}
到这里,一个最简单的溶解效果就已经完成了。
如果我们将渐变图换成噪声图(Noise Texture),则就可以做出更随机的溶解了。
噪声图
效果如下:
Comments