Dissolve1-3
该方法的效果好坏在于噪声纹理的分布。本例利用SD的Blend节点,将Noise贴图和渐变贴图进行正片叠底操作,并简单调整边缘边缘大小,得到如下所示的噪声贴图。
制作的遮罩为四周较暗,且对角线轴向向内亮度递增,使得最终的溶解效果从四周向内部溶解。
Shader "Custom/DissolveShader" {
Properties {
_MainTex ("Main Texture", 2D) = "white" { }
_DissolveMap ("Noise Map", 2D) = "white" { }
_DissolveFactor ("Dissolve Factor", Range(0, 18)) = 0.5
_Diffuse ("Diffuse Color", Color) = (1, 1, 1, 1)
_DissolveColor ("Dissolve Color", Color) = (1, 0, 0, 1)
_DissolveBoundaryBegin ("Dissolve Boundary Begin", Range(0.3, 1)) = 0.4
_DissolveBoundaryEnd ("Dissolve Boundary End", Range(0.3, 0.4)) = 0.3
_DissolveBoundaryAlpha ("Dissolve Boundary Alpha", Range(0, 1)) = 0.5
}
SubShader {
Tags { "Queue" = "Geometry+1" "RenderType" = "Opaque" }
pass {
Blend SrcAlpha OneMinusSrcAlpha
Tags { "LightMode" = "ForwardBase" }
CGPROGRAM
#include "UnityCG.cginc"
#include "Lighting.cginc"
#pragma vertex vert
#pragma fragment frag
fixed4 _Diffuse;
sampler2D _MainTex;
float4 _MainTex_ST;
sampler2D _DissolveMap;
float4 _DissoveMap_ST;
float _DissolveFactor;
fixed4 _DissolveColor;
float _DissolveBoundaryBegin;
float _DissolveBoundaryEnd;
float _DissolveBoundaryAlpha;
struct v2f {
float4 pos : SV_POSITION;
float3 worldNormal : TEXCOORD2;
float2 uv : TEXCOORD0;
float4 screenPos : TEXCOORD1;
};
v2f vert(appdata_base v) {
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.uv = v.texcoord;
o.worldNormal = UnityObjectToWorldNormal(v.normal);
o.screenPos = ComputeGrabScreenPos(o.pos);
return o;
}
fixed4 frag(v2f i) : SV_Target {
// 采样噪声贴图的值
fixed dissolveTex = tex2D(_DissolveMap, i.uv).r;
// 计算光照
fixed3 worldNormal = normalize(i.worldNormal);
fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);
fixed3 lambert = saturate(dot(worldNormal, worldLightDir));
fixed3 albedo = lambert * _Diffuse.xyz * _LightColor0.xyz + UNITY_LIGHTMODEL_AMBIENT.xyz;
fixed3 color = albedo * tex2D(_MainTex, i.uv).rgb;
// 利用时间实现一个简单的动态效果
fixed dissolveFactor = _DissolveFactor * abs(lerp(-1, 1, frac(_Time.y * 0.1)));
// 利用消融因子为消融贴图赋值,使其整体灰度值随着消融因子的变化而变化
fixed alpha = saturate(dissolveTex * dissolveFactor * dissolveFactor);
// 判断当前的透明度 若在设定范围内则更改颜色 并同时更改透明度方便后续bloom效果实现
if (alpha < _DissolveBoundaryBegin && alpha > _DissolveBoundaryEnd) {
return fixed4(_DissolveColor.rgb, _DissolveBoundaryAlpha);
} else if (alpha < _DissolveBoundaryEnd) {
alpha = 0;
}
return fixed4(color, alpha);
}
ENDCG
}
}
FallBack "Diffuse"
}
利用cllip方法强制中止当前渲染过程,达到透视效果。由于clip方法的使用,导致无法进行early-z等操作,在手机端会有较大的性能开销。
Shader "Custom/Dissolve2Shader" {
Properties {
_MainTex ("Albedo (RGB)", 2D) = "white" { }
_Diffuse ("Diffuse Color", Color) = (1, 1, 1, 1)
_Range ("Range", Range(0, 1)) = 0.1
}
SubShader {
Tags { "RenderType" = "Opaque" }
pass {
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma target 3.0
#include "UnityCG.cginc"
#include "Lighting.cginc"
float _Range;
sampler2D _MainTex;
float4 _Diffuse;
struct v2f {
float4 pos : SV_POSITION;
float3 worldNormal : TEXCOORD2;
float2 uv : TEXCOORD0;
float4 screenPos : TEXCOORD1;
};
v2f vert(appdata_base v) {
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.uv = v.texcoord;
o.worldNormal = UnityObjectToWorldNormal(v.normal);
o.screenPos = ComputeScreenPos(o.pos);
return o;
}
fixed4 frag(v2f i) : SV_Target {
float2 wcoord = (i.screenPos.xy / i.screenPos.w);
// 记得再乘以屏幕的像素个数,才能最终得到屏幕位置
wcoord *= _ScreenParams.xy;
// 随时间变化 * _Time.y * 3
float changeRange = _Range;
// screenPos *0.5 是为了方便当两数相加时有奇偶的区分,
// 若和为奇数,则乘以0.5再取小数部分则小数部分必为0.5,若为偶数,再乘0.5则小数部分为0
float2 screenPos = floor(wcoord.xy * changeRange) * 0.5;
// 棋盘图案中 4x4 像素块的 checker 值为负
float checker = -frac(screenPos.r + screenPos.g);
// 如果clip函数中的值为负数,则停止渲染
clip(checker);
// 计算光照
fixed3 worldNormal = normalize(i.worldNormal);
fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);
fixed3 lambert = saturate(dot(worldNormal, worldLightDir));
fixed3 albedo = lambert * _Diffuse.xyz * _LightColor0.xyz + UNITY_LIGHTMODEL_AMBIENT.xyz;
// 对于保留的像素,读取纹理并将其输出
fixed3 color = albedo * tex2D(_MainTex, i.uv).rgb;
return fixed4(color, 1);
}
ENDCG
}
}
FallBack "Diffuse"
}
该方法同样利用clip方法达到消融的目的,距离的运算在世界空间中完成,消融的实现在屏幕空间中完成。
这里最后一句话有点没看懂 再琢磨琢磨。
Shader "Custom/Dissolve3Shader" {
Properties {
_MainTex ("Albedo (RGB)", 2D) = "white" { }
_Diffuse ("Diffuse Color", Color) = (1, 1, 1, 1)
_FogNear ("Fog Near", float) = 1.0
_FogFar ("Fog Far", float) = 1.0
_Test ("Test", float) = 1.0
}
SubShader {
Tags { "RenderType" = "Opaque" }
pass {
Blend SrcAlpha OneMinusSrcAlpha
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma target 3.0
#include "UnityCG.cginc"
#include "Lighting.cginc"
sampler2D _MainTex;
float4 _Diffuse;
float _FogFar;
float _FogNear;
float _Test;
struct appdata {
float4 vertex : POSITION;
float2 uv1 : TEXCOORD0;
float2 uv2 : TEXCOORD1;
float3 normal : NORMAL;
};
struct v2f {
float4 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
float3 worldPos : TEXCOORD1;
float4 screenPos : TEXCOORD2;
float3 worldNormal : TEXCOORD3;
};
v2f vert(appdata v) {
v2f o;
// 裁剪空间坐标
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv.xy = v.uv1;
o.uv.zw = v.uv2;
// 屏幕空间坐标
o.screenPos = ComputeScreenPos(o.vertex);
// 世界空间坐标
o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
o.worldNormal = UnityObjectToWorldNormal(v.normal);
return o;
}
fixed4 frag(v2f i) : SV_Target {
// 计算光照
fixed3 worldNormal = normalize(i.worldNormal);
fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);
fixed3 lambert = saturate(dot(worldNormal, worldLightDir));
fixed3 albedo = lambert * _Diffuse.xyz * _LightColor0.xyz + UNITY_LIGHTMODEL_AMBIENT.xyz;
fixed4 color = fixed4(albedo * tex2D(_MainTex, i.uv).rgb,tex2D(_MainTex, i.uv).a);
// 物体顶点距离相机距离
float distanceRamp = distance(i.worldPos, _WorldSpaceCameraPos.xyz);
// 利用Smoothstep对距离进行约束
distanceRamp = smoothstep(_FogNear, _FogFar, distanceRamp);
// 构建抖动顺序矩阵
float4x4 thresholdMatrix = {
1.0 / 17.0, 9.0 / 17.0, 3.0 / 17.0, 11.0 / 17.0,
13.0 / 17.0, 5.0 / 17.0, 15.0 / 17.0, 7.0 / 17.0,
4.0 / 17.0, 12.0 / 17.0, 2.0 / 17.0, 10.0 / 17.0,
16.0 / 17.0, 8.0 / 17.0, 14.0 / 17.0, 6.0 / 17.0
};
// 获取屏幕空间坐标(归一化
float2 screenPos = i.screenPos.xy / i.screenPos.w;
// 0-1的坐标范围乘以画面像素总数
screenPos *= _ScreenParams.xy;
// 依据动态抖动计算透明度
half noise = distanceRamp - thresholdMatrix[fmod(screenPos.x, 4 * _Test)] * thresholdMatrix[fmod(screenPos.y, 4 * _Test)];
clip(noise);
return color;
}
ENDCG
}
}
FallBack "Diffuse"
}