RoadLun原創,轉載請聲明
~~~~~~~~~~~~······ ~~~~~多圖預警~~~~~~~~~~~~~~~~~~~~~~~~~·
效果:
Gif不清楚,先看一張靜態圖
噪波律動法球:
流動法球:
旋轉法球:
實現:
1.上訴所有效果均爲在片段函數/着色函數中改變UV的映射方式實現,首先需要新建一個球體,接下來的效果將體現在這個球體上
2.需要一張帶有Alpha通道的半透明貼圖(如下貼圖,右鍵圖片另存爲即可使用,CSDN有2M限制,所以圖片被壓縮過)
因爲此圖是PNG格式,將圖片直接拖到球體上即可看到變爲半透明球體:
OK看起來沒錯~ 但其實此時自動生成的材質球附着的Shader是一個unity自帶的只讀的Shader,無法進行操作,所以還是按照步驟來吧!
3.新建一個Shader(此處我使用頂點/片段着色器,所以新建一個ImageEffectShader或UnlitShader)。要想實現半透明效果,首先開啓透明度混合,設置渲染隊列爲Transparent(半透明),開啓Cull Off
Blend One ONE
CULL OFF
Tags{"Queue"="Transparent"}
4.實現原理:由易到難,先講流動法球(動圖2),此處我用的是頂點/片段着色器,在片段着色器的UV映射階段,使原本的UV映射的X、Y值隨時間增大而增大:
sampler2D _MainTex;
float _WaveSpeed;
fixed4 frag (v2f i) : SV_Target
{
float2 tmpUV=i.uv;
tmpUV.y+= _WaveSpeed*_Time.y; //核心步驟
//tmpUV.x+=_WaveSpeed*_Time.x; //核心步驟
fixed4 col = tex2D(_MainTex,tmpUV);
return col;
}
流動效果就是如此簡單,接下來講解旋轉法球,也就是貼圖UV旋轉:UV可以理解成一個二維座標系,長寬可看作X,Y軸,此處我按照(0.5,0.5)爲圓心進行旋轉,所以先將UV貼圖位移(-0.5,-0.5),用矩陣旋轉後再位移(0.5,0.5)。關於矩陣旋轉
sampler2D _MainTex;
float _Speed;
fixed4 frag (v2f i) : SV_Target
{
float2 tmpUV =i.uv;
tmpUV -=float2(0.5,0.5); //變換旋轉中心
float2 angle =_Time*_Speed; //角度隨時間變化而變化
float2 result =float2(0,0); //創建一個容器
result.x =tmpUV.x * cos(angle) -sin(angle)*tmpUV.y; //公式
result.y =tmpUV.x * sin(angle) +cos(angle)*tmpUV.y; //公式
tmpUV+=float2(0.5,0.5); //旋轉中心迴歸
fixed4 col = tex2D(_MainTex, result);
// just invert the colors
//col = 1 - col;
return col;
}
如上效果就實現貼圖旋轉功能。接下來是噪波律動法球(動圖1),這個視覺效果就複雜一點了,
仔細看球表面有火苗一般的搖曳:
這是通過噪聲圖來影響UV映射到某個像素的位置,噪聲圖可以理解爲一個包含很多隨機數的集合,噪聲圖上某個區域(或某個像素)的灰度值就是一個隨機數。通過這個隨機數,影響UV映射到像素上的位置。
噪聲圖:
下圖做個比較:
接下來讓採樣的噪波圖UV隨時間偏移,就有了gif上的效果。片段函數如下:
uniform float _SpeedX;
uniform float _SpeedY;
uniform float _NoiseStrength;
float4 frag(VertexOutput i) : COLOR {
//光照函數
i.normalDir = normalize(i.normalDir);
float3 normalDirection = i.normalDir;
float3 lightDirection = normalize(_WorldSpaceLightPos0.xyz);
float3 lightColor = _LightColor0.rgb;
float attenuation = LIGHT_ATTENUATION(i);
float3 attenColor = attenuation * _LightColor0.xyz;
float NdotL = max(0.0,dot( normalDirection, lightDirection ));
float3 directDiffuse = max( 0.0, NdotL) * attenColor;
float3 indirectDiffuse = float3(0,0,0);
indirectDiffuse += UNITY_LIGHTMODEL_AMBIENT.rgb;
//x,y方向流動
float2 FlowUV = (i.uv0+float2((_SpeedX*_Time.g),(_Time.g*_SpeedY)));
float4 _NoiseMap_var = tex2D(_NoiseMap,TRANSFORM_TEX(FlowUV, _NoiseMap));
//噪波強度
float2 NoiseUV = (i.uv0+(float2(_NoiseMap_var.r,_NoiseMap_var.g)*_NoiseStrength));
float4 _MainTex_var = tex2D(_MainTex,TRANSFORM_TEX(NoiseUV, _MainTex));
float3 diffuseColor = _MainTex_var.rgb;
float3 diffuse = (directDiffuse + indirectDiffuse) * diffuseColor;
float3 finalColor = diffuse;
fixed4 finalRGBA = fixed4(finalColor,1);
UNITY_APPLY_FOG(i.fogCoord, finalRGBA);
return finalRGBA;
}
源碼:下面是三個Shader的源碼:
1.流動法球特效(動圖2)
Shader "Custom/Flow"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_WaveSpeed("貼圖移速",float)=3
}
SubShader
{
Blend One ONE
CULL OFF
Tags{"Queue"="Transparent"}
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};
//下面是頂點着色器,有四個可控量,控制振幅、波長、頻率、偏移
float _Frequency;
float _Attruibte;
float _K2;
float _B2;
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = v.uv;
return o;
}
//下面是片段着色器 控制像素的移動
sampler2D _MainTex;
float _WaveSpeed;
fixed4 frag (v2f i) : SV_Target
{
float2 tmpUV=i.uv;
tmpUV.y+= _WaveSpeed*_Time.y;
//tmpUV.x+=_WaveSpeed*_Time.x;
fixed4 col = tex2D(_MainTex,tmpUV);
return col;
}
ENDCG
}
}
}
2.旋轉法球特效(動圖三)
Shader "Custom/Rotate"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_Speed("旋轉速度",Float)=1
}
SubShader
{
cull off
Blend SrcAlpha One
Tags{"Queue"="Geometry+2"}
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = v.uv;
return o;
}
//像素的矩陣旋轉
//思路:
//1.先將旋轉中心設爲(0.5,0.5) 默認中心爲(0,0)
//2.套用旋轉公式
//3.旋轉完畢,中心回到(0,0)
sampler2D _MainTex;
float _Speed;
fixed4 frag (v2f i) : SV_Target
{
float2 tmpUV =i.uv;
tmpUV -=float2(0.5,0.5); //變換旋轉中心
float2 angle =_Time*_Speed; //角度隨時間變化而變化
float2 result =float2(0,0); //創建一個容器
result.x =tmpUV.x * cos(angle) -sin(angle)*tmpUV.y; //套公式
result.y =tmpUV.x * sin(angle) +cos(angle)*tmpUV.y; //套公式
tmpUV+=float2(0.5,0.5); //旋轉中心迴歸
fixed4 col = tex2D(_MainTex, result);
// just invert the colors
//col = 1 - col;
return col;
}
ENDCG
}
}
}
// 關於矩陣旋轉的公式: X: 1 0 0 0 (A爲隨時間變化而變化的角度,下同)
// 0 cosA -sinA 0
// 0 sinA cosA 0
// 0 0 0 1
// Y: cosA 0 sinA 0
// 0 1 0 0
// -sinA 0 cosA 0
// 0 0 0 1
// Z: cosA -sinA 0 0
// sinA cosA 0 0
// 0 0 1 0
// 0 0 0 1
3.噪波律動法球(動圖一)
Shader "Custom/NoiseFlow" {
Properties {
_MainTex ("主紋理", 2D) = "bump" {}
_NoiseMap ("噪聲圖", 2D) = "bump" {}
_SpeedX("x方向速度",float)=0.02
_SpeedY("y方向速度",float)=0.02
_NoiseStrength ("噪波強度",float)=0.1
}
SubShader {
Blend One One
//Blend SrcAlpha OneMinusSrcAlpha
Cull Off
Tags {
"Queue"="Transparent"
}
Pass {
Name "FORWARD"
Tags {
"LightMode"="ForwardBase"
}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#define UNITY_PASS_FORWARDBASE
#include "UnityCG.cginc"
#include "AutoLight.cginc"
#pragma multi_compile_fwdbase_fullshadows
#pragma multi_compile_fog
#pragma only_renderers d3d9 d3d11 glcore gles
#pragma target 3.0
uniform float4 _LightColor0;
uniform sampler2D _MainTex; uniform float4 _MainTex_ST;
uniform sampler2D _NoiseMap; uniform float4 _NoiseMap_ST;
struct VertexInput {
float4 vertex : POSITION;
float3 normal : NORMAL;
float2 texcoord0 : TEXCOORD0;
};
struct VertexOutput {
float4 pos : SV_POSITION;
float2 uv0 : TEXCOORD0;
float4 posWorld : TEXCOORD1;
float3 normalDir : TEXCOORD2;
};
VertexOutput vert (VertexInput v) {
VertexOutput o = (VertexOutput)0;
o.uv0 = v.texcoord0;
o.normalDir = UnityObjectToWorldNormal(v.normal);
o.posWorld = mul(unity_ObjectToWorld, v.vertex);
float3 lightColor = _LightColor0.rgb;
o.pos = UnityObjectToClipPos( v.vertex );
UNITY_TRANSFER_FOG(o,o.pos);
TRANSFER_VERTEX_TO_FRAGMENT(o)
return o;
}
uniform float _SpeedX;
uniform float _SpeedY;
uniform float _NoiseStrength;
float4 frag(VertexOutput i) : COLOR {
//光照函數
i.normalDir = normalize(i.normalDir);
float3 normalDirection = i.normalDir;
float3 lightDirection = normalize(_WorldSpaceLightPos0.xyz);
float3 lightColor = _LightColor0.rgb;
float attenuation = LIGHT_ATTENUATION(i);
float3 attenColor = attenuation * _LightColor0.xyz;
float NdotL = max(0.0,dot( normalDirection, lightDirection ));
float3 directDiffuse = max( 0.0, NdotL) * attenColor;
float3 indirectDiffuse = float3(0,0,0);
indirectDiffuse += UNITY_LIGHTMODEL_AMBIENT.rgb;
//x,y方向流動
float2 FlowUV = (i.uv0+float2((_SpeedX*_Time.g),(_Time.g*_SpeedY)));
float4 _NoiseMap_var = tex2D(_NoiseMap,TRANSFORM_TEX(FlowUV, _NoiseMap));
//噪波強度
float2 NoiseUV = (i.uv0+(float2(_NoiseMap_var.r,_NoiseMap_var.g)*_NoiseStrength));
float4 _MainTex_var = tex2D(_MainTex,TRANSFORM_TEX(NoiseUV, _MainTex));
float3 diffuseColor = _MainTex_var.rgb;
float3 diffuse = (directDiffuse + indirectDiffuse) * diffuseColor;
float3 finalColor = diffuse;
fixed4 finalRGBA = fixed4(finalColor,1);
UNITY_APPLY_FOG(i.fogCoord, finalRGBA);
return finalRGBA;
}
ENDCG
}
}
FallBack "Diffuse"
}
寫完~