消融效果

消融效果是模拟物体逐渐从屏幕上消失或溶解的过程,它通常利用噪声纹理实现,使物体按照某种规则逐渐透明或完全不可见。这种效果常用于: 角色死亡、传送场景、 魔法消失,比如燃烧、消失等

1、基本原理

通过对比噪声纹理值与消融进度参数,剔除低于阈值的像素,同时在边缘添加渐变颜色实现动态溶解效果。
关键点:

  • 如何剔除像素

在片元着色器中对噪声纹理进行采样,由于噪声纹理是灰度图,只需取出其中的RGB中的任意一通道的颜色来使用。再自定义一个用于控制消融进度的参数(0~1),最后利用该片元的 噪声纹理值 – 进度参数,若小于0则不渲染该片元,通过控制进度参数,便可以控制消融程度了

  • 如何处理边缘

在处理边缘渐变颜色效果时,将使用Unity中内置的三个Shader函数:


smoothstep(a, b, x)

a起始值;b结束值;x输入值(用于在a和b之间平滑插值)
当x<a时,返回0;当x>b时,返回1;
a < x < b时,返回0~1之间的值


lerp(a,b,t)
a起始值;b结束值;t插值因子
当t=0时,返回a;当t=1时,返回b;当 0 < t < 1时;返回a和b之间的值


step(value, x)
value阈值,x输入值;两值用于比较
x < value,返回0;x>=value,返回1


首先我们利用smoothstep函数决定边缘颜色,利用噪声颜色值 – 消融进度值 得到一个剔除阈值value,然后自定义一个边缘范围值_Range,然后用smoothstep函数来得到一个值

接着在原本的颜色和渐变颜色之间进行插值,决定使用哪个颜色。

利用smoothstep结合消融阈值来决定在渐变纹理中采用的渐变颜色,利用lerp来决定在原始颜色和边缘渐变颜色中使用哪个颜色,用自定义参数来决定边缘范围,从而实现消融边缘渐变色

2、实现

Shader "ShaderProj/21/Dissolve"
{
    Properties
    {
        _MainTex ("MainTex", 2D) = "white" {}
        _MainColor ("MainColor", Color) = (1,1,1,1)
        _BumpMap("BumpMap", 2D) = ""{}
        _BumpScale("BumpScale", Range(0, 1)) = 1
        _SpecularColor("SpecularColor", Color) = (1,1,1,1)
        _SpecularNum("SpecularNum", Range(8, 256)) = 18

        _Noise ("Noise", 2D) = ""{}
        _Gradient ("Gradient", 2D) = ""{}
        _Dissolve ("Dissolve", Range(0, 1)) = 0
        _EdgeRange ("EdgeRange", Range(0, 1)) = 0
    }
    SubShader
    {
        Pass
        {
            Tags { "LightMode"="ForwardBase" }
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma multi_compile_fwdbase
            #include "UnityCG.cginc"
            #include "Lighting.cginc"
            #include "AutoLight.cginc"

            struct v2f
            {
                float4 uv : TEXCOORD0;
                float4 pos : SV_POSITION;
                float3 lightDir : TEXCOORD1;
                float3 viewDir : TEXCOORD2;
                float2 uvNoise : TEXCOORD3;
                float3 worldPos : TEXCOORD4;
                SHADOW_COORDS(5)
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;
            fixed4 _MainColor;
            sampler2D _BumpMap;
            float4 _BumpMap_ST;
            float _BumpScale;
            fixed4 _SpecularColor;
            fixed _SpecularNum;
            sampler2D _Noise;
            float4 _Noise_ST;
            sampler2D _Gradient;
            fixed _Dissolve;
            fixed _EdgeRange;

            v2f vert (appdata_full v)
            {
                v2f data;
                data.pos = UnityObjectToClipPos(v.vertex);
                data.uv.xy = TRANSFORM_TEX(v.texcoord, _MainTex);
                data.uv.zw = TRANSFORM_TEX(v.texcoord, _BumpMap);
                data.uvNoise = TRANSFORM_TEX(v.texcoord, _Noise);

                float3 binormal = cross(normalize(v.tangent), normalize(v.normal)) * v.tangent.w;
                float3x3 rotation = float3x3(v.tangent.xyz,
                                             binormal,
                                             v.normal);
                data.lightDir = mul(rotation, ObjSpaceLightDir(v.vertex));
                data.viewDir = mul(rotation, ObjSpaceViewDir(v.vertex));
                data.worldPos = mul(unity_ObjectToWorld, v.vertex);

                TRANSFER_SHADOW(data);
                return data;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                // 剔除
                fixed3 noiseColor = tex2D(_Noise, i.uvNoise);
                clip(_Dissolve == 1 ? -1 : noiseColor - _Dissolve);

                float4 packedNormal = tex2D(_BumpMap, i.uv.zw);
                float3 tangentNormal = UnpackNormal(packedNormal);
                tangentNormal.xy *= _BumpScale;
                tangentNormal.z = sqrt(1.0 - saturate(dot(tangentNormal.xy, tangentNormal.xy)));

                fixed3 albedo = tex2D(_MainTex, i.uv.xy) * _MainColor.rgb;
                fixed3 lambertColor = _LightColor0.rgb * albedo.rgb * max(0, dot(tangentNormal, normalize(i.lightDir)));
                float3 halfA = normalize(normalize(i.viewDir) + normalize(i.lightDir));
                fixed3 specularColor = _LightColor0.rgb * _SpecularColor.rgb * pow(max(0, dot(tangentNormal, normalize(i.viewDir))), _SpecularNum);

                UNITY_LIGHT_ATTENUATION(atten, i, i.worldPos);

                fixed3 color = UNITY_LIGHTMODEL_AMBIENT.rgb * albedo + lambertColor * atten + specularColor;

                // 渐变颜色
                fixed t = 1 - smoothstep(0, _EdgeRange, noiseColor - _Dissolve);
                fixed3 gradient = tex2D(_Gradient, fixed2(t, 0));
                fixed3 finalColor = lerp(color, gradient, t * step(0.00001, _Dissolve));

                return fixed4(finalColor, 1);
            }
            ENDCG
        }
        Pass{
            Tags{"LightMode" = "ShadowCaster"}
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma multi_compile_shadowcaster
            #include "UnityCG.cginc"

            struct v2f
            {
                V2F_SHADOW_CASTER;
                fixed2 uvNoise : TEXCOORD0;
            };

            sampler2D _Noise;
            float4 _Noise_ST;
            float _Dissolve;

            v2f vert(appdata_base v)
            {
                v2f data;
                data.uvNoise = TRANSFORM_TEX(v.texcoord, _Noise); 
                TRANSFER_SHADOW_CASTER_NORMALOFFSET(data);
                return data;
            }

            fixed4 frag(v2f i) : SV_Target
            {
                // 剔除影子
                fixed3 noiseColor = tex2D(_Noise, i.uvNoise);
                clip(_Dissolve == 1 ? -1 : noiseColor - _Dissolve);
                SHADOW_CASTER_FRAGMENT(i);
            }

            ENDCG
        }
    }
}

### 实现Logo消融效果的方法 为了创建精美的Logo消融效果,可以利用Unity中的粒子系统来模拟这种视觉现象。具体来说,在Unity环境中设置并配置粒子系统的各个组件能够达到理想的效果[^1]。 #### 配置粒子发射器属性 首先定义一个基本的粒子系统作为发射源。通过调整`Emission`模块下的参数控制粒子数量随时间变化规律,比如线性增长或指数衰减模式下逐渐增加粒子数目直至形成完整的图形覆盖整个Logo区域[^3]。 #### 设定初始速度与方向 接着设定粒子初速度及其分布范围,这决定了它们离开源头后的运动轨迹。对于消融效果而言,通常希望粒子沿随机角度向外扩散,因此可以在`Shape`模块里指定合适的形状(如圆盘形),并通过调节`Speed over Lifetime`使不同生命周期阶段内的粒子具有各异的速度特性[^2]。 #### 添加颜色渐变过渡 为了让消散过程看起来更加自然流畅,还需要精心设计色彩的变化逻辑。借助于`Color Over Lifetime`功能赋予每个存活期内的个体从明亮到暗淡乃至透明度降低的过程,从而营造出一种物质慢慢消失不见的感觉。 #### 应用纹理贴图增强质感 如果追求更高级别的真实感,则可考虑引入自定义Sprite序列或者单张带有Alpha通道信息的大尺寸图片资源充当粒子外观素材;再配合上Material材质球里的Shader着色程序进一步优化渲染质量,最终达成令人满意的艺术风格呈现。 ```csharp // C#脚本用于动态管理粒子系统行为 using UnityEngine; public class LogoDissolveEffect : MonoBehaviour { private ParticleSystem ps; void Start() { ps = GetComponent<ParticleSystem>(); var main = ps.main; main.startLifetime = 2f; // 设置粒子生命期长度 var emission = ps.emission; emission.rateOverTime = new ParticleSystem.MinMaxCurve(0, 5); // 控制单位时间内产生的新成员数上限 var colorOverLifetime = ps.colorOverLifetime; Gradient gradient = new Gradient(); gradient.SetKeys( new[] { Color.white, Color.clear }, new[] { 0.0f, 1.0f } ); colorOverLifetime.color = gradient; // 定义由白至无的颜色演变路径 } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值