top of page
作家相片Lingheng Tao

Unity Shader #8 Dissolve

已更新:1月15日


这篇主要写一下关于各种溶解算法的使用,以及消解算法延伸出来的材质过度,还有在 Unity 中用 C# 脚本控制消解的简单框架。



最基本的简单溶解


所谓的溶解都可以被分成三个部分:

  1. 未溶解的部分:完全不透明,保持原有固有色。

  2. 已溶解的部分:完全透明,不可见。

  3. 溶解边缘:溶解部分的边界,可能会发光、可能不平整。

因此,最基本的溶解效果我们就遵循这个思路。

 

算法概括

  1. 采样渐变图。用一个 Property 去控制实际的黑白区域,用 step 确定未溶解和已溶解的部分。

  2. 确认边缘区域。离溶解边缘近的区域的边缘判定值为 1。

  3. 越接近边缘,颜色越靠近边缘的颜色;否则,则靠近采样的固有色。

 

步骤一 采样渐变图,将渐变图的 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),则就可以做出更随机的溶解了。

噪声图

效果如下:



34 次查看0 則留言

Comments


bottom of page