消融效果
消融广泛运用于各种场合,例如
- 怪物击杀与道具时区(原神)
- 燃烧
注意:根据噪声图的不同,效果有很大的差异,
第一步:创建着色器
我们要选择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 100Pass{Tags {"LightMode" = "ForwardBase"}//内部裸露,要开启双面渲染Cull OffCGPROGRAM#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
}
}}