DungDaj 发表于 2022-2-16 14:21

Unity Shader 片段舍弃实现溶解效果(附源码)

大家好,我是老莫,今天分享一下溶解效果的制作方法。
首先定义clip和color属性
_MainTex ("Texture", 2D) = "white" {}
      _Color ("Color",Color) =(1,1,1,1)
      _Clip("Clip",Range(0,1)) = 0
因为我们要做片段舍弃,所以将Clip运算放在片段着色器中

http://pic1.zhimg.com/v2-6e9e5e7980eb788fbbd1ae4209364a24_r.jpg

X代表一个数值,当X<0时,则舍弃掉此片段.

括号中的X就是我们要舍弃掉的片段值,当X<0时,该片段舍弃

http://pic2.zhimg.com/v2-099e22533feda0b7075f113e9469f909_r.jpg

只有当x<0,片段才会舍弃

当X为某个数值时,只能实现所有像素的取舍,那么我们想要部分像素舍弃,达到溶解效果,就需要这样一张噪波图。

http://pic2.zhimg.com/v2-81a83077d7d068e2cec01e40f21747dd_r.jpg

网上随意找一张噪波图即可

这样做的原理是,噪波图中数值代表了一个Range(0,1),任何一个像素都被限制在这个范围内,并且随机分布,此时我们将噪波图减去一个Range(0,1),就可以控制最终的值了。
属性面板添加一个-DissolveTex,在片段着色器采样它,然后使用采样后的图减去Clip值
fixed4 tex = tex2D(_MainTex,i.uv);

                fixed4 dissolveTex = tex2D(_DissolveTex,i.uv);
                clip(dissolveTex-_Clip);

http://pic2.zhimg.com/v2-ac55c95958d262bdaa4af5c9bdcfb13d_r.jpg

不同Clip值所产生的的效果

现在对该效果进行优化,增加一个溶解边缘
我们需要这样一张贴图 _RampTex



PS中随便制作一个即可

我们做这张图的目的在于,将_DissolveTex中从0到1(黑到白)与_RampTex中从左到右对应,听起来有点莫名其妙,慢慢往下看。
使用_DissolveTex采样上图
fixed4 tex = tex2D(_MainTex,i.uv);
                fixed4 dissolve = tex2D(_DissolveTex,i.uv);
                fixed4 ramptex = tex2D(_RampTex,dissolve);
                clip(dissolve-_Clip);
                fixed4 c = tex * _Color+ramptex;
                return c;

http://pic4.zhimg.com/v2-663c101910f2ae8eb58f77b12764beaf_r.jpg
创建一个平面可以更直观地看到效果,请注意现在我们已完成了_DissolveTex中从0到1(黑到白)与_RampTex中从左到右对应。但是目前边缘没有随着溶解的值变化,这里我们需要用到unity内置函数smoothstep。
如果 x 比min 小,返回 0;如果 x 比max 大,返回 1;如果 x 处于范围 中,则返回 0 和 1 之间的值(按值在min和max间的比例取平滑值)。
smoothstep(min,max,x)

我们将_Clip设为最小值,再配合_Clip值变化,就可以使溶解边缘始终都是从_RampTex的最左边开始采样
                fixed4 tex = tex2D(_MainTex,i.uv);
                fixed4 dissolve = tex2D(_DissolveTex,i.uv);
                fixed4 ramptex = tex2D(_RampTex,smoothstep(_Clip,1,dissolve));
                clip(dissolve-_Clip);
                fixed4 c = tex * _Color+ramptex;

http://pic3.zhimg.com/v2-227dec08af2cd8c8602f1d2e58900b16_r.jpg
这时我们的溶解边缘正确了,但是_RampTex覆盖了主纹理.
在上一步中,我们将最小值设为_Clip,得以控制边缘,现在我们把最大值设为_Clip+0.1,这样使得我们只在_clip 和_clip+0.1之间采样_RampTex



clip=0.2

划重点
现在我们实现了溶解效果,基本了解了原理,但是以上方法计算量较大(smoothstep),现在我们讲讲如何优化。首先我们看一下smoothstep 的原理
float smoothstep (float min, float max, float x)
{
        float t = saturate ((x - min) / (max - min));
        return t * t * (3.0 - (2.0 * t));
}
其中return t * t *(3.0-(2.0* t));是为了使最终值平滑,运算量太大,我们可以把这一步省掉,直接手写差值,使用saturate
fixed4 tex = tex2D(_MainTex,i.uv);

                fixed4 dissolveTex = tex2D(_DissolveTex,i.uv);
                clip(dissolveTex-_Clip);
                fixed dissolvevalue = saturate(dissolveTex-_Clip)/(_Clip+0.1-_Clip);
                fixed4 ramptex = tex2D(_RampTex,dissolvevalue);
                fixed4 c = tex * _Color+ramptex;
                return c;


http://pic3.zhimg.com/v2-f9592bf7f394c55e1cf8876200d4e9f2_r.jpg
到这里unity shader中的溶解效果就完成了,收工。

最后附上源码
Shader "Unlit/rongjie"
{
    Properties
    {
      _MainTex ("Texture", 2D) = "white" {}
      _Color ("Color",Color) =(1,1,1,1)
      _Clip("Clip",Range(0,1)) = 0
      _DissolveTex("DissolveTex",2D) = "white"{}
      _RampTex ("RampTex",2D) = "white"{}
    }
    SubShader
    {
      Tags { "RenderType"="Opaque" }
      LOD 100

      Pass
      {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                float4 pos : SV_POSITION;
            };

            sampler2D _MainTex;
            sampler2D _DissolveTex;
            sampler2D _RampTex;
            float4 _MainTex_ST;
            fixed4 _Color;
            float _Clip;

            v2f vert (appdata v)
            {
                v2f o;
                o.pos = UnityObjectToClipPos(v.vertex);
                o.uv = v.uv;
               
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                fixed4 tex = tex2D(_MainTex,i.uv);

                fixed4 dissolveTex = tex2D(_DissolveTex,i.uv);
                clip(dissolveTex-_Clip);
                fixed dissolvevalue = saturate(dissolveTex-_Clip)/(_Clip+0.1-_Clip);
                fixed4 ramptex = tex2D(_RampTex,dissolvevalue);
                fixed4 c = tex * _Color+ramptex;
                return c;
            }
            ENDCG
      }
    }
}

BlaXuan 发表于 2022-2-16 14:30

进我收藏夹吃会[思考]
页: [1]
查看完整版本: Unity Shader 片段舍弃实现溶解效果(附源码)