概述
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"
}
写完~
最后
以上就是柔弱悟空为你收集整理的Shader 能量法球特效的全部内容,希望文章能够帮你解决Shader 能量法球特效所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复