Shader实例(流光实现)
流光效果
首先来看一下流光效果。流光效果是一个非常常见的效果,不仅仅是游戏,一些广告之类的也都会有这种效果。流光的原理还是比较简单的:首先就是需要一张流光图,这张流光图的大部分都是黑色,然后有一条亮线,然后我们在采样的时候,最终输出叠加上这张图的采样值,并根据时间调整采样的UV就可以有流光的效果啦。下面是一个比较简单的流光效果实现:
下面看属性参数:
接下来是SubShader中的一些参数定义
顶点函数处理
光照处理
以上是对于2D图像常用的流光实现方式,如果是3D物体用这种方式的话,可能会出现问题,所以对于3D物体,采用按照物体的世界坐标按时间偏移查询纹理贴图就行了
具体参数按需求改下就好了
按照方向消失或重现效果
我们再来看一个用模型空间坐标作为采样的uv的栗子,也是一种比较好玩的效果。比如我们需要一个模型身体按照一定的方向逐渐消失,直至全部消失掉的一个效果。下面说一下思路,与世界空间采样的流光效果一样,我们在vertex阶段记录一下vertex坐标,传递给fragment阶段,在fragment阶段用这个值和一个设定好的阈值进行比较,不满足条件的像素点直接discard,逐渐调整阈值,就可以得到让模型按照某个方向消失的效果了。代码如下:
-
-
-
- Shader "SelfShader/DissolveEffectX"
- {
- Properties
- {
- _MainTex("MainTex(RGB)", 2D) = "white" {}
- _DissolveVector("DissolveVector", Vector) = (0,0,0,0)
- }
-
- CGINCLUDE
- #include "Lighting.cginc"
- uniform sampler2D _MainTex;
- uniform float4 _MainTex_ST;
- uniform float4 _DissolveVector;
-
- struct v2f
- {
- float4 pos : SV_POSITION;
- float3 worldNormal : NORMAL;
- float2 uv : TEXCOORD0;
- float3 worldLight : TEXCOORD1;
- float4 objPos : TEXCOORD2;
- };
-
- v2f vert(appdata_base v)
- {
- v2f o;
- o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
- o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
-
- o.objPos = v.vertex;
- o.worldNormal = UnityObjectToWorldNormal(v.normal);
- o.worldLight = UnityObjectToWorldDir(_WorldSpaceLightPos0.xyz);
- return o;
- }
-
- fixed4 frag(v2f i) : SV_Target
- {
- half3 normal = normalize(i.worldNormal);
- half3 light = normalize(i.worldLight);
- fixed diff = max(0, dot(normal, light));
- fixed4 albedo = tex2D(_MainTex, i.uv);
-
- clip(i.objPos.xyz - _DissolveVector.xyz);
- fixed4 c;
- c.rgb = diff * albedo;
- c.a = 1;
- return c;
- }
- ENDCG
-
- SubShader
- {
-
- Pass
- {
- Tags{ "RenderType" = "Opaque" }
-
- CGPROGRAM
- #pragma vertex vert
- #pragma fragment frag
- ENDCG
- }
- }
- FallBack "Diffuse"
- }
还有一个小问题,其实上图中的例子里面,模型从上到下,理想情况应该是调整Y轴,不过例子里面调整的确实X轴,原因应该与Unity导入之后会绕着X轴旋转90度有关,也就是原本在max里面的Y轴变成Unity里面的X轴。
下面,我们再看一下增加了边缘高亮的消失效果,为了让模消失的型边缘高亮,我们通过将用于clip的factor值与另一个高亮阈值值进行比较,如果factor小于高亮阈值,则返回一个高亮的颜色值,否则正常渲染。这样模型就总共有三种显示状态:clip状态,高亮状态,正常状态。代码如下:
-
-
-
-
- Shader "SelfShader/DissolveEffectX"
- {
- Properties{
- _Diffuse("Diffuse", Color) = (1,1,1,1)
- _DissolveColor("Dissolve Color", Color) = (0,0,0,0)
- _MainTex("Base 2D", 2D) = "white"{}
- _ColorFactor("ColorFactor", Range(0,1)) = 0.7
- _DissolveThreshold("DissolveThreshold", Float) = 0
- }
-
- CGINCLUDE
- #include "Lighting.cginc"
- uniform fixed4 _Diffuse;
- uniform fixed4 _DissolveColor;
- uniform sampler2D _MainTex;
- uniform float4 _MainTex_ST;
- uniform float _ColorFactor;
- uniform float _DissolveThreshold;
-
- struct v2f
- {
- float4 pos : SV_POSITION;
- float3 worldNormal : TEXCOORD0;
- float2 uv : TEXCOORD1;
- float4 objPos : TEXCOORD2;
- };
-
- v2f vert(appdata_base v)
- {
- v2f o;
- o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
- o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
- o.worldNormal = mul(v.normal, (float3x3)unity_WorldToObject);
- o.objPos = v.vertex;
- return o;
- }
-
- fixed4 frag(v2f i) : SV_Target
- {
- float factor = i.objPos.x - _DissolveThreshold;
- clip(factor);
-
- 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 = tex2D(_MainTex, i.uv).rgb * albedo;
-
- fixed lerpFactor = saturate(sign(_ColorFactor - factor));
- return lerpFactor * _DissolveColor + (1 - lerpFactor) * fixed4(color, 1);
-
-
-
-
-
-
- }
- ENDCG
-
- SubShader
- {
- Tags{ "RenderType" = "Opaque" }
- Pass
- {
-
- Cull Off
- CGPROGRAM
- #pragma vertex vert
- #pragma fragment frag
- ENDCG
- }
- }
- FallBack "Diffuse"
- }
溶解效果进阶版
之前的文章里,我们研究过
溶解效果,不过这个效果是基于全身的,我们来尝试一下,把上面按照方向消失的效果与溶解效果结合起来,做成一个按照某个方向逐渐溶解的效果。要得到随机的溶解效果,我们需要采样一张噪声图,然后在原本会直接clip掉的部分根据采样的噪声图进行clip,就能得到按照方向的溶解效果啦。
-
-
-
-
- Shader "SelfShader/DissolveEffectX"
- {
- Properties{
- _Diffuse("Diffuse", Color) = (1,1,1,1)
- _DissolveColor("Dissolve Color", Color) = (1,1,1,1)
- _MainTex("Base 2D", 2D) = "white"{}
- _DissolveMap("DissolveMap", 2D) = "white"{}
- _DissolveThreshold("DissolveThreshold", Range(0,1)) = 0
- _DissolveSpeedFactor("DissolveSpeed", Range(0,5)) = 2
- _DissolveControl("ColorFactorB", Float) = 0
- }
-
- CGINCLUDE
- #include "Lighting.cginc"
- uniform fixed4 _Diffuse;
- uniform fixed4 _DissolveColor;
- uniform sampler2D _MainTex;
- uniform float4 _MainTex_ST;
- uniform sampler2D _DissolveMap;
- uniform float _DissolveThreshold;
- uniform float _DissolveSpeedFactor;
- uniform float _DissolveControl;
-
- struct v2f
- {
- float4 pos : SV_POSITION;
- float3 worldNormal : TEXCOORD0;
- float2 uv : TEXCOORD1;
- float4 objPos : TEXCOORD2;
- };
-
- v2f vert(appdata_base v)
- {
- v2f o;
- o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
- o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
- o.worldNormal = mul(v.normal, (float3x3)unity_WorldToObject);
- o.objPos = v.vertex;
- return o;
- }
-
- fixed4 frag(v2f i) : SV_Target
- {
- fixed4 dissolve = tex2D(_DissolveMap, i.uv);
-
- 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 = tex2D(_MainTex, i.uv).rgb * albedo;
- float factor = i.objPos.x - _DissolveControl;
- if(factor < 0)
- {
- clip(_DissolveThreshold - dissolve.r * abs(factor) * _DissolveSpeedFactor);
- }
- return fixed4(color, 1);
- }
- ENDCG
-
- SubShader
- {
- Tags{ "RenderType" = "Opaque" }
- Pass
- {
- Cull Off
- CGPROGRAM
- #pragma vertex vert
- #pragma fragment frag
- ENDCG
- }
- }
- FallBack "Diffuse"
- }
Shader "SelfShader/Dissolve"
{
Properties
{
_MainColor("MainColor",COLOR)=(1,1,1,1)
_MainTex ("Texture", 2D) = "white" {}
_Noise("Noise",2D)="white"{}
_Dissolve("Dissolve",Vector)=(0.2,0.5,0.8)
_DissolveThread("DissolveThread",float)=0.2
_DissolveColor("DissolveColor",COLOR)=(1,1,1,1)
_DissolveColFactor("_DissolveColFactor",float)=2
_FlyFactor("FlyFactor",float)=3
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 100
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#include "Lighting.cginc"
struct a2v
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
fixed3 normal:NORMAL;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 pos : SV_POSITION;
fixed3 worldNormal:TEXCOORD1;
fixed3 worldPos:TEXCOORD2;
fixed3 objPos:TEXCOORD3;
};
sampler2D _Noise;
sampler2D _MainTex;
float4 _MainTex_ST;
fixed4 _MainColor;
fixed4 _Dissolve;
float _DissolveThread;
fixed4 _DissolveColor;
float _DissolveColFactor;
float _FlyFactor;
v2f vert (a2v v)
{
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.worldPos=mul((float3x3)unity_ObjectToWorld,v.vertex);
o.worldNormal=UnityObjectToWorldNormal(v.normal);
o.objPos=v.vertex;
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
o.pos.xyz+=v.normal*saturate(_DissolveThread-_FlyFactor)*_FlyFactor;
return o;
}
fixed4 frag (v2f i) : SV_Target
{
fixed3 worldNor=normalize(i.worldNormal);
fixed3 lightDir=normalize(_WorldSpaceLightPos0.xyz);
fixed4 albedo = tex2D(_MainTex, i.uv)*_MainColor;
fixed4 noiseColor=tex2D(_Noise,i.uv);
float factor=noiseColor.r-_DissolveThread;
clip(factor);
fixed3 ambient=UNITY_LIGHTMODEL_AMBIENT.xyz*albedo.rgb;
fixed3 diffuse=_LightColor0.rgb*albedo.rgb*(0.5*dot(lightDir,worldNor)+0.5);
float lerpFactor=saturate(sign(_DissolveColFactor-factor));
return lerp(fixed4(ambient+diffuse,1),_DissolveColor,lerpFactor);
}
ENDCG
}
}
}