Unity Shader 消融效果

该文详细介绍了如何在Unity3D中创建一个自定义的UnlitShader,实现物体的消融效果。首先,通过定义MainTex、NoiseMap等属性来设置材质。接着,传入法线信息以计算漫反射。最后,在像素着色器中计算消融的程度,结合环境光和漫反射光,生成消融过渡的视觉效果。
摘要由CSDN通过智能技术生成

在这里插入图片描述

消融效果

消融广泛运用于各种场合,例如

  1. 怪物击杀与道具时区(原神)
  2. 燃烧
    注意:根据噪声图的不同,效果有很大的差异,
    在这里插入图片描述
    在这里插入图片描述

在这里插入图片描述

第一步:创建着色器

我们要选择Unlit Shader创建

然后定义如下属性

Properties
    {
    	//主贴图
        _MainTex ("Texture", 2D) = "white" {}
        //噪声图
        _NoiseMap ("NoiseMap", 2D) = "white" {}
        //第一种颜色
        _Color_First ("DissolveColorFirst", Color) = (1, 0, 0, 1)
        //第二种颜色
        _Color_Second ("DissolveColorSecond", Color) = (1, 0, 0, 1)
		//过渡宽度
        _Width ("LineWidth", Range(0,1)) = 0
        //消融程度
        _Value ("Amount", Range(0,1)) = 0
        //反射光颜色
        _Diffuse("Diffuse", Color) = (1, 1, 1, 1)
    }

这里注意,请加上这个,不然单面渲染使得模型内部裸露

Cull Off 

第二步:传入法线

只有这样我们才能计算漫反射


//修改默认的结构体
    struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
                //添加Normal的传递
                float3 normal: NORMAL;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                UNITY_FOG_COORDS(1)
                float4 vertex : SV_POSITION;
                //自定义的法线信息
                float3 worldNormal : TEXCOORD1; // 添加了 worldNormal 属性
            };



  		// 将 变量 声明在全局范围
		 sampler2D _MainTex;
            float4 _MainTex_ST;
            sampler2D _NoiseMap;
            float _Value ;
            float _Width ;
            float4 _Color_First;
            float4 _Color_Second;
            fixed4 _Diffuse;
	
			//要从顶点着色器开始就传入法线
            v2f vert(appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                //这句是自己写的,将法线信息传递下去
                o.worldNormal = normalize(UnityObjectToWorldNormal(v.normal));
                UNITY_TRANSFER_FOG(o, o.vertex);
                return o;
            }

第三步:裁剪像素和计算漫反射

这一步的作用是先算出光线的效果,然后跟消融后的效果混合,而不是仅仅有消融的效果

 fixed4 frag(v2f i) : SV_Target
            {
                //计算灰度值
                float gray = dot(tex2D(_NoiseMap, i.uv).rgb, float3(0.299, 0.587, 0.114));
                //剔除完全消融像素
                clip(gray - _Value);

                //获取环境光的属性并标准化
                fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
                //标准化世界坐标下光源的光照方向
                fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);
                //计算漫反射光照
                fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(i.worldNormal, worldLightDir));

                //计算点是否在过渡区域以及混合系数
                fixed t = 1 - smoothstep(0.0, _Width, gray - _Value);
                //根据混合系数计算消融颜色
                fixed3 dissolveColor = lerp(_Color_First, _Color_Second, t);
                dissolveColor = pow(dissolveColor, 5);


                fixed3 origin = tex2D(_MainTex,i.uv);
                // 最终颜色 = (源色+环境光 + 漫反射光照 ) 和消融色的插值
                fixed3 finalColor =lerp(origin+ ambient + diffuse,dissolveColor,t *step(0.0001, _Value));

                // 应用雾效
                UNITY_APPLY_FOG(i.fogCoord, finalColor);
                return fixed4(finalColor, 1.0);
            }

完整着色器代码

Shader "Custom/Dissolve"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
        _NoiseMap ("NoiseMap", 2D) = "white" {}
        _Color_First ("DissolveColorFirst", Color) = (1, 0, 0, 1)
        _Color_Second ("DissolveColorSecond", Color) = (1, 0, 0, 1)

        _Width ("LineWidth", Range(0,1)) = 0
        _Value ("Amount", Range(0,1)) = 0
        _Diffuse("Diffuse", Color) = (1, 1, 1, 1)
    }
    SubShader
    {
        Tags 
        { 
            "RenderType"="Opaque"  
            "LightMode"="ForwardBase" 
        }
        LOD 100

        Pass
        {
            Tags 
            {
                "LightMode" = "ForwardBase"
            }
            //内部裸露,要开启双面渲染
            Cull Off
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            // 让雾效生效
            #pragma multi_compile_fog

            #include "UnityCG.cginc"
            #include "Lighting.cginc"
            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
                //添加Normal的传递
                float3 normal: NORMAL;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                UNITY_FOG_COORDS(1)
                float4 vertex : SV_POSITION;
                //自定义的法线信息
                float3 worldNormal : TEXCOORD1; // 添加了 worldNormal 属性

            };

            sampler2D _MainTex;
            float4 _MainTex_ST;
            sampler2D _NoiseMap;

            // 将 _Value 声明在全局范围
            float _Value ;
            float _Width ;
            float4 _Color_First;
            float4 _Color_Second;


            fixed4 _Diffuse;

            v2f vert(appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                o.worldNormal = normalize(UnityObjectToWorldNormal(v.normal));
                UNITY_TRANSFER_FOG(o, o.vertex);
                return o;
            }

            fixed4 frag(v2f i) : SV_Target
            {
                //计算灰度值
                float gray = dot(tex2D(_NoiseMap, i.uv).rgb, float3(0.299, 0.587, 0.114));
                //剔除完全消融像素
                clip(gray - _Value);

                //获取环境光的属性并标准化
                fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
                //标准化世界坐标下光源的光照方向
                fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);
                //计算漫反射光照
                fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(i.worldNormal, worldLightDir));

                //计算点是否在过渡区域以及混合系数
                fixed t = 1 - smoothstep(0.0, _Width, gray - _Value);
                //根据混合系数计算消融颜色
                fixed3 dissolveColor = lerp(_Color_First, _Color_Second, t);
                dissolveColor = pow(dissolveColor, 5);


                fixed3 origin = tex2D(_MainTex,i.uv);
                // 最终颜色 = (环境光 + 漫反射光照 ) 和消融色的插值
                fixed3 finalColor =lerp(origin+ ambient + diffuse,dissolveColor,t *step(0.0001, _Value));

                // 应用雾效
                UNITY_APPLY_FOG(i.fogCoord, finalColor);
                return fixed4(finalColor, 1.0);
            }
            ENDCG
        }

        Pass
{
    Tags { "LightMode" = "ShadowCaster" }

    Name "shadowCaster"

    CGPROGRAM
    ...

    struct v2f
    {
        //frag需要的shadowCaster信息,包括位置、bias、depth等
        V2F_SHADOW_CASTER;
        //noise map的纹理坐标
        float2 uv0 : TEXCOORD0;
    };

    v2f vert(appdata_base v)
    {
        v2f o;
        //完成:
        //1.UnityClipSpaceShadowCasterPos:根据模型空间pos和normal,计算裁剪空间阴影位置,与光照配置中的NormalBias有关(unity_LightShadowBias.z==NormalBias)
        //2.UnityApplyLinearShadowBias:增加裁剪空间中Z值。与光照参数中的Bias、UNITY_NEAR_CLIP_VALUE、UNITY_REVERSED_Z有关
        TRANSFER_SHADOW_CASTER_NORMALOFFSET(o)
        //根据缩放和偏移计算noise map纹理坐标
        o.uv0 = TRANSFORM_TEX(v.texcoord, _NoiseMap);

        return o;
    }

    fixed4 frag(v2f i) : SV_Target
    {
        //采样noise,与阈值比较,未通过不显示阴影
        fixed3 noise = tex2D(_NoiseMap, i.uv0).rgb;
        clip(noise.r - _DissolveThreshold);
        //平行光、聚光灯情况下返回 0(黑色)
        //点光源情况下调用UnityEncodeCubeShadowDepth得到cubemap shadow值
        SHADOW_CASTER_FRAGMENT(i)
    }

    ENDCG
}
}



}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

YUE ZHEN PENG

码字不易,如果你想请我喝杯果汁

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值