使用噪声贴图或者程序噪声,经过范围0-1的float材质参数在片元着色器进行 clip 操做。算法
float _DissolveDegree; // 材质参数:溶解程度 // fbm 程序噪声生成 float test = fbm(i.uv) - _DissolveDegree; clip(test);
使用hdr、渐变纹理(RampTexture)、bloom提升效果。app
程序噪声参考 link动画
Shader "DissolvePack/unlit/DissolveSh" { Properties { _MainTex ("Texture", 2D) = "white" {} _RampTexture ("Ramp Texture", 2D) = "white" {} _Color("Tint", Color) = (1,1,1,1) _Color2("Burn Color", Color) = (1,1,1,1) _DissolveDegree("Dissolve Degree", Range(0,1)) = 0 _DissolveOffset("Dissolve Offset", Range(0.0, 0.5)) = 0.15 } SubShader { Tags { "RenderType"="Opaque" } LOD 100
3dPass { CGPROGRAM #pragma vertex vert #pragma fragment frag // make fog work #pragma multi_compile_fog #include "UnityCG.cginc" // 程序噪声 https://thebookofshaders.com/13/?lan=ch #include "../Noise.cginc" struct appdata { float4 vertex : POSITION; float2 uv : TEXCOORD0; }; struct v2f { float2 uv : TEXCOORD0; UNITY_FOG_COORDS(1) float4 vertex : SV_POSITION; }; sampler2D _MainTex,_RampTexture; float4 _MainTex_ST; float _DissolveDegree,_DissolveOffset; float4 _Color,_Color2; v2f vert (appdata v) { v2f o; o.vertex = UnityObjectToClipPos(v.vertex); o.uv = TRANSFORM_TEX(v.uv, _MainTex); UNITY_TRANSFER_FOG(o,o.vertex); return o; } fixed4 frag (v2f i) : SV_Target { // sample the texture fixed4 color = tex2D(_MainTex, i.uv); fixed4 col = saturate(color*_Color); fixed4 burnColor = saturate(color*_Color2); float test = fbm(i.uv) - _DissolveDegree; clip(test); if(test < _DissolveOffset && _DissolveDegree > 0) { //col = burnColor; col = tex2D(_RampTexture, float2(test/_DissolveOffset,0)); } // apply fog UNITY_APPLY_FOG(i.fogCoord, col); return col; } ENDCG } }}Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag // make fog work #pragma multi_compile_fog #include "UnityCG.cginc" // 程序噪声 https://thebookofshaders.com/13/?lan=ch #include "../Noise.cginc" struct appdata { float4 vertex : POSITION; float2 uv : TEXCOORD0; }; struct v2f { float2 uv : TEXCOORD0; UNITY_FOG_COORDS(1) float4 vertex : SV_POSITION; }; sampler2D _MainTex,_RampTexture; float4 _MainTex_ST; float _DissolveDegree,_DissolveOffset; float4 _Color,_Color2; v2f vert (appdata v) { v2f o; o.vertex = UnityObjectToClipPos(v.vertex); o.uv = TRANSFORM_TEX(v.uv, _MainTex); UNITY_TRANSFER_FOG(o,o.vertex); return o; } fixed4 frag (v2f i) : SV_Target { // sample the texture fixed4 color = tex2D(_MainTex, i.uv); fixed4 col = saturate(color*_Color); fixed4 burnColor = saturate(color*_Color2); float test = fbm(i.uv) - _DissolveDegree; clip(test); if(test < _DissolveOffset && _DissolveDegree > 0) { //col = burnColor; col = tex2D(_RampTexture, float2(test/_DissolveOffset,0)); } // apply fog UNITY_APPLY_FOG(i.fogCoord, col); return col; } ENDCG } }
有些游戏的类型(eg:卡通)可能不须要平滑的溶解边缘,让边缘的颜色不是平滑渐进而是以相似{0,0.2,0.4,0.6...}阶梯式的渐进。code
float _BandingSize; // 材质参数:带状大小,渐进值为 1 / _BandingSize,eg:_BandingSize = 5,则为{0,0.2,0.4,0.6...} round(fbm(uv)*_BandingSize)/_BandingSize
使用uv生成噪声时,让小数位的精度丢失。orm
float pixelSize = 10; float noise = fbm(floor(uv*pixelSize));
模型坐标与方向(vector材质参数,归一化)进行点乘,越偏离方向值越小。blog
half test = (dot(objectPosition, normalize(_DissolveDir))+ 1) / 2 - _DissolveDegree; clip(test);
溶解3d模型时反面会被剔除(cull),关闭剔除时效果:游戏
方面溶解使用VFACE自定义剔除面:图片
frag(fixed facing:VFACE){ if(facing < 0) 颜色赋值. }
使用模型坐标旋转时方向会同时跟随着变化,缩放会致使offset变化。ip
改用忽略掉位移的世界坐标(即以模型坐标原点和世界坐标原点重合)即可以让方向不受模型旋转,缩放的影响。
vert { // 矩阵变换的第四列是位移变化,强转为float3x3便会忽略位移变换。 float3 worldPos = mul((float3x3)unity_ObjectToWorld, vertex.xyz); }
Shader "Unlit/DirectionalDissolveSh" { Properties { _MainTex ("Texture", 2D) = "white" {} _RampTexture ("Ramp Texture", 2D) = "white" {} _DissolveDir("Dissolve Direction", vector) = (0,0,0,0) _DissolveDegree("Dissolve Degree", Range(0,1)) = 0 _DissolveOffset("Dissolve Offset", Range(0.0, 0.5)) = 0.15 _NoiseST("Noise Scale & Offset", vector) = (1,1,0,0) [HDR]_Tint("Tint", Color) = (1,1,1,1) } SubShader { Tags { "RenderType"="Opaque" } LOD 100
Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag // make fog work #pragma multi_compile_fog #include "UnityCG.cginc" // 程序噪声 https://thebookofshaders.com/13/?lan=ch #include "../Noise.cginc" struct appdata { float4 vertex : POSITION; float2 uv : TEXCOORD0; }; struct v2f { float2 uv : TEXCOORD0; float3 worldPosAdj : TEXCOORD1; UNITY_FOG_COORDS(1) float4 vertex : SV_POSITION; }; sampler2D _MainTex,_RampTexture; float4 _MainTex_ST; float4 _DissolveDir; float4 _Tint; float4 _NoiseST; float _DissolveDegree, _DissolveOffset; v2f vert (appdata v) { v2f o; o.vertex = UnityObjectToClipPos(v.vertex); o.uv = TRANSFORM_TEX(v.uv, _MainTex); o.worldPosAdj = mul((float3x3)unity_ObjectToWorld, v.vertex.xyz); //o.worldPosAdj = v.vertex; UNITY_TRANSFER_FOG(o,o.vertex); return o; } fixed4 frag (v2f i) : SV_Target { // sample the texture fixed4 col = tex2D(_MainTex, i.uv); // [-1,1] => [0,1] half test = (dot(i.worldPosAdj, normalize(_DissolveDir))+ 1) / 2 - _DissolveDegree; clip(test); float noise = fbm(i.uv*_NoiseST.xy+_NoiseST.zw); test = test*noise - 0.01; clip (test); float offset = _DissolveOffset*0.1; if(test < offset && _DissolveDegree > 0) { col = tex2D(_RampTexture, float2(test/offset,0)) * _Tint; } // apply fog UNITY_APPLY_FOG(i.fogCoord, col); return col; } ENDCG } }}Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag // make fog work #pragma multi_compile_fog #include "UnityCG.cginc" // 程序噪声 https://thebookofshaders.com/13/?lan=ch #include "../Noise.cginc" struct appdata { float4 vertex : POSITION; float2 uv : TEXCOORD0; }; struct v2f { float2 uv : TEXCOORD0; float3 worldPosAdj : TEXCOORD1; UNITY_FOG_COORDS(1) float4 vertex : SV_POSITION; }; sampler2D _MainTex,_RampTexture; float4 _MainTex_ST; float4 _DissolveDir; float4 _Tint; float4 _NoiseST; float _DissolveDegree, _DissolveOffset; v2f vert (appdata v) { v2f o; o.vertex = UnityObjectToClipPos(v.vertex); o.uv = TRANSFORM_TEX(v.uv, _MainTex); o.worldPosAdj = mul((float3x3)unity_ObjectToWorld, v.vertex.xyz); //o.worldPosAdj = v.vertex; UNITY_TRANSFER_FOG(o,o.vertex); return o; } fixed4 frag (v2f i) : SV_Target { // sample the texture fixed4 col = tex2D(_MainTex, i.uv); // [-1,1] => [0,1] half test = (dot(i.worldPosAdj, normalize(_DissolveDir))+ 1) / 2 - _DissolveDegree; clip(test); float noise = fbm(i.uv*_NoiseST.xy+_NoiseST.zw); test = test*noise - 0.01; clip (test); float offset = _DissolveOffset*0.1; if(test < offset && _DissolveDegree > 0) { col = tex2D(_RampTexture, float2(test/offset,0)) * _Tint; } // apply fog UNITY_APPLY_FOG(i.fogCoord, col); return col; } ENDCG } }
在溶解的过程加上形变即顶点移动。
vert { float3 worldPosAdj = mul(unity_ObjectToWorld, vertex.xyz); float posRatio = (dot(worldPosAdj, dir) + 1 ) / 2; vertex.xyz += dir * fbm(uv) * _DissolveDegree * posRatio * _ChangeSize; }
主要操做都在片元着色器里;溶解图片使用噪声也可使用贴图,贴图能够多种多样,甚至是帧动画图片;因为不参与光照计算,sprite的颜色变化须要手动处理,处理方法能够是相似于数字图像处理之类的方法,也能够与扰动贴图相关联;Sprite的溶解一样可使用适用于3d的溶解;因为sprite有部分透明区域,渲染模式也是透明的,全部裁剪能够经过a通道。
// 材质参数 float _DissolveDegree; // 溶解程度 float _DissolveOffset; // 溶解边缘宽度 float4 _NoiseST; // 噪声缩放和平移 float4 _TargetColor; // 总体变化颜色 // 修改透明度,且让边缘颜色有渐进效果 float4 c = smoothstep(_DissolveDegree, _DissolveDegree + _DissolveOffset, fbm(uv * _NoiseST.xy + _NoiseST.zw)); color *= c; // 总体颜色变化 color.rgb = lerp(color.rgb, color.rgb * (1 - color.a) + _TargetColor.rgb, _DissolveDegree); // 相乘效果也还行 color.rgb = lerp(color.rgb, color.rgb * (1 - color.a) * _TargetColor.rgb * 20, _DissolveDegree);
使用uv参数,可配方向一样使用dot。
float2 dir = normalize(float2(_DissolveDir.x,_DissolveDir.y)); float test = (dot(dir,uv - float2(0.5,0.5))+1)/2 - _DissolveDegree;
因为uv是固定的,不像坐标那么不可控,能够经过程序算法生成一些特殊的边缘变化。
// eg float offset = _DissolveDegree*sin(uv.x*5*3.14); float test = (1 + offset)*(1-uv.y)/(_DissolveDegree + 0.01);
一种是直接使用噪声贴图图的像素值影响uv(distortion),让主帖图具备噪声贴图的形状。而后sprite逐渐溶解(透明值、或使用噪声、或者使用方向溶解都行)。
eg: 2dxfx上的blood的简化版,只保留了扭曲(distortion)和方向溶解(directional dissolve)。
另外一种是使用噪声贴图的各个通道,每一个通道是不一样的形状,在不一样时段影响主贴图,而后合并在一块儿。2dxfx上的那几个teleportion基本上都是使用这种方法,再加上闪光(shiny)之类的效果合并而成。最终效果依赖于贴图的选择制做。