Unity3D消融效果shader实现

实现思路

消融效果首先需要一张噪声图,噪声图可以用一些软件来生成例如ps,也可以自己写噪声算法来生成。
获得噪声图之后,在shader中对噪声纹理的亮度值进行采样,丢弃小于阈值的片元。
还需要添加一些补充效果,例如表现烧焦的边缘之类的,这也可以通过一个亮度的比较再加上插值来完成。

噪声图

简单起见,我们直接使用PS来生成,打开PS的工具栏。滤镜->渲染->分层云彩。之后再添加图层进行一些调色,得到我们使用的噪声图。

在这里插入图片描述

如果想要自己来生成噪声图,也可以查阅perlin噪声算法相关的资料。

clip函数

关键代码也很简单
tex2D对_NoiseTex噪声图进行采样,此时获得的是rgb值,使用abs获取亮度值。之后使用clip函数和_Threshold阈值进行比较,就可以丢弃小于阈值的片元。

fixed burnAmount = abs(tex2D(_NoiseTex, i.uvNoise));
clip(burnAmount - _Threshold);

添加了简单的lambert漫反射模型。此时效果如下
在这里插入图片描述

边缘烧焦效果

有时候可能还需要一些更加艺术化的处理,例如边缘的烧焦效果。
大致就是离被丢弃的片元越近的片元,它就烧焦的更多(需要定义一个烧焦的颜色。)这里就直接用噪声纹理的亮度值减掉阈值,结果值越大,说明离烧焦的边缘越远。
最后使用lerp函数进行插值就可以了。这里还使用了min函数,确保lerp函数的第三个参数小于1,不然会出现奇怪的效果。

float burnEdge = burnAmount - _Threshold;
diffuse = lerp(_BurnColor, diffuse, min(1, burnEdge * _BurnColorExpand));

最终调整参数后效果如下
在这里插入图片描述
在这里插入图片描述
还可以用一个脚本来动态调整阈值,造成一种物体渐渐被烧光的错觉,这也可以搭配粒子效果。

 void Update()
    {
        material.SetFloat("_Threshold",threshold);
        threshold += Time.deltaTime/10f;
    }

在这里插入图片描述

完整代码

Shader "LX/dissolve"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
        _NoiseTex("NoiseTex",2D)="white"{}
        _Threshold("Threshold",float)=0.5
        _BurnColor("BurnColor",color)=(1,1,1,1)
        _BurnColorExpand("BurnColorExpand",float)=1
    }
    SubShader
    {
        Tags
        {
            "RenderType"="Opaque"
        }
        LOD 100
        Cull Off
        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

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

            struct v2f
            {
                float2 uvMain : TEXCOORD0;
                float4 vertex : SV_POSITION;
                fixed worldLightDir:TEXCOORD1;
                fixed worldNormal:TEXCOORD2;
                float2 uvNoise : TEXCOORD3;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;

            sampler2D _NoiseTex;
            float4 _NoiseTex_ST;

            float _Threshold;
            float3 _BurnColor;

            float _BurnColorExpand;

            v2f vert(appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uvMain = TRANSFORM_TEX(v.uv, _MainTex);
                o.uvNoise = TRANSFORM_TEX(v.uv, _NoiseTex);
                float4 worldPos = mul(unity_ObjectToWorld, v.vertex);
                o.worldLightDir = UnityWorldSpaceLightDir(worldPos);
                o.worldNormal = UnityObjectToWorldNormal(v.normal);
                return o;
            }

            fixed4 frag(v2f i) : SV_Target
            {
                fixed burnAmount = abs(tex2D(_NoiseTex, i.uvNoise));
                clip(burnAmount - _Threshold);

                fixed3 worldLightDir = i.worldLightDir;
                fixed3 worldNormal = i.worldNormal;

                fixed4 col = tex2D(_MainTex, i.uvMain);
                fixed3 diffuse = dot(worldLightDir, worldNormal) * col;

                float burnEdge = burnAmount - _Threshold;
                diffuse = lerp(_BurnColor, diffuse, min(1, burnEdge * _BurnColorExpand));

                return fixed4(diffuse, 0);
            }
            ENDCG
        }
    }
}

另外代码也传到github仓库里了,大家也可以关注一下哦~
我的github

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值