——20.9.14
Shader中主要有及兩種影片,一種就是紋理影片還有一種就是頂點影片,
影片效果一般都需要把時間加入一些變數的計算,以便畫面可以隨時間發生變化,下面是Shader中的如何去訪問時間的方法,

一、紋理影片
序列幀影片就是我們接觸的第一種紋理影片,序列幀影片原理就是依次播放一系列關鍵幀影片,當圖片的切換速度達到一定數值后,看上去就像是連續的影片,優點:在于它的靈活性強,不用進行物理計算就會有對應的影片效果,缺點:依舊是需要逐關鍵幀的影片內容,作業量依舊很大,
我們看看shaderlab部分,我們需要看有什么樣的變數,一般來說序列幀一般是一張圖片包括了所有的關鍵幀,并且按播放順序排放,并且方便讀取一般是規整的(就是沒有邊框),所以我們要確定有幾行_HorizontalAmount幾列_VerticalAmount根據圖片決定,還有就是播放速度_Speed,最后就是圖片_MainTex,和顏色_Color,
//frag
float time = floor(_Time.y * _Speed);
float row = floor(time / _HorizontalAmount);
float column = time - row * _VerticalAmount; half2 uv = float2(i.uv.x / _HorizontalAmount, i.uv.y / _VerticalAmount); uv.x += column / _HorizontalAmount; uv.y -= row / _VerticalAmount; //half2 uv = i.uv + half2(column, -row); //uv.x /= _HorizontalAmount; //uv.y /= _VerticalAmount;
首先是_Time.y就是取時間變數t,然后通過取整來確定行數,然后通過取小數來確定列數,這里是在片元著色器中的兩種讀取方式,一種是根據行和列把坐標放大到整張圖片,并且通過增加基礎單位來進行可以看到對uv.y進行的是減操作,是因為unity里面是從左下為(0,0),然后第二種方法先去確定要讀取的行列,然后再去細分到一個區間內,要注意上面這兩種方法本質上都是為了取這張關鍵幀中的一張圖片,于是就要把uv坐標縮放到其中的一張,
Shader "Unlit/11-1ImageSequenceAnimation"
{
Properties
{
_Color ("Color", Color) = (1,1,1,1)
_MainTex ("Texture", 2D) = "white" {}
_HorizontalAmount ("HorizontalAmount", Float) = 4
_VerticalAmount ("VerticalAmount", Float) = 4
_Speed ("Speed", Range(1, 100)) = 30
}
SubShader
{
Tags { "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" }
Pass
{
Tags { "LightMode"="ForwardBase" }
ZWrite off
Blend SrcAlpha OneMinusSrcAlpha
CGPROGRAM
#pragma multi_compile_fwdbase
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 texcoord : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 pos : SV_POSITION;
};
sampler2D _MainTex;
float4 _MainTex_ST;
fixed4 _Color;
float _VerticalAmount;
float _HorizontalAmount;
float _Speed;
v2f vert (appdata v)
{
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
return o;
}
fixed4 frag (v2f i) : SV_Target
{
float time = floor(_Time.y * _Speed);
float row = floor(time / _HorizontalAmount);
float column = time - row * _VerticalAmount;
half2 uv = float2(i.uv.x / _HorizontalAmount, i.uv.y / _VerticalAmount);
uv.x += column / _HorizontalAmount;
uv.y -= row / _VerticalAmount;
//half2 uv = i.uv + half2(column, -row);
//uv.x /= _HorizontalAmount;
//uv.y /= _VerticalAmount;
fixed4 c = tex2D(_MainTex, uv);
c.rgb *= _Color;
return c;
}
ENDCG
}
}FallBack "Transparent/VertexLit"
}
下面就是針對不同的行列,相同的速度數值也是截然不同的速度,


然后就是不同的背景進遠景對應的速度不同,我們看一下首先需要兩張圖分別是近景和遠景_MainTex _DetailTex,然后就是分別他們的速度_ScrollX _Scroll2X,最后就是有關亮度_Multiplier,
T frac(T v)
//vert o.uv.xy = TRANSFORM_TEX(v.texcoord, _MainTex) + frac(float2(_ScrollX, 0.0)) * _Time.y; o.uv.zw = TRANSFORM_TEX(v.texcoord, _DetailTex) + frac(float2(_Scroll2X, 0.0)) * _Time.y;
fixed4 c = lerp(firstLayer, secondLayer, secondLayer.a);
frac函式是回傳變數的小數部分,其中的變數可以是float float2 float3 float4 都會分別對變數取小數,這樣可以保證圖片可以回圈播放,因為上面每一個頂點取偏移值值是一樣的,然后需要混合顏色采用的lerp然后第三個變數取的是secondlayer的a通道是因為這種圖是一張黑白圖取值分別就是1或者0,便可以確定近景中哪一些是鏤空可以放遠景的顏色,
Shader "Unlit/11-2ScrollingBackground"
{
Properties
{
_MainTex ("BaseLayer(RGB)", 2D) = "white" {}
_DetailTex ("2ndLayer(RGB)", 2D) = "white" {}
_ScrollX ("BaseLayerScrollSpeed", Float) = 1.0
_Scroll2X ("2ndLayerScrollSpeed", Float) = 1.0
_Multiplier ("LayerMultiplier", Float) = 1
}
SubShader
{
Tags { "RenderType"="Opaque" "Queue"="Geometry" }
Pass
{
Tags { "LightMode"="ForwardBase" }
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 texcoord : TEXCOORD0;
};
struct v2f
{
float4 uv : TEXCOORD0;
float4 pos : SV_POSITION;
};
sampler2D _MainTex;
float4 _MainTex_ST;
sampler2D _DetailTex;
float4 _DetailTex_ST;
float _ScrollX;
float _Scroll2X;
float _Multiplier;
v2f vert (appdata v)
{
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.uv.xy = TRANSFORM_TEX(v.texcoord, _MainTex) + frac(float2(_ScrollX, 0.0)) * _Time.y;
o.uv.zw = TRANSFORM_TEX(v.texcoord, _DetailTex) + frac(float2(_Scroll2X, 0.0)) * _Time.y;
return o;
}
fixed4 frag (v2f i) : SV_Target
{
fixed4 firstLayer = tex2D(_MainTex, i.uv.xy);
fixed4 secondLayer = tex2D(_DetailTex, i.uv.zw);
fixed4 c = lerp(firstLayer, secondLayer, secondLayer.a);
c.rgb *= _Multiplier;
return c;
}
ENDCG
}
}FallBack "VertexLit"
}

二、頂點影片
我們先做一個2d的頂點影片,就是河流,我們看一下我們需要河流的紋理_MainTex,_Color調整整體顏色,控制水流動的幅度_Magniture,水流的波動_Frequency,波長的倒數_InvWaveLength(即該值越大,波長越小),流動速度_Speed.
Tags { "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" "DisableBatching"="True" }
//vert
offset.yzw = float3(0,0,0);
offset.x = sin(_Frequency * _Time.y + v.vertex.x * _InvWaveLength + v.vertex.y * _InvWaveLength + v.vertex.z * _InvWaveLength) * _Magnitude;
DisableBatching關閉該tags是為了指明是否要對該SubShader進行批處理,因為這些需要特殊處理的Shader基本包括頂點影片,會合并與之相關的模型導致相關的頂點出現問題,合并模型會導致各自模型空間丟失(留個坑?),頂點影片本質就是改變其中的頂點著色器中頂點的位置,這個的vertex是模型空間中的加上模型空間的位置分量,
Shader "Unlit/11-3Water"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_Color ("Color", Color) = (1,1,1,1)
_Magnitude ("Distortion Magnitude", Float) = 1
_Frequency ("Distortion Frequency", Float) = 1
_InvWaveLength ("InvWaveLength", Float) = 10
_Speed ("Speed", Float) = 0.5
}
SubShader
{
Tags { "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" "DisableBatching"="True" }
Pass
{
Tags { "LightMode"="ForwardBase" }
ZWrite Off
Blend SrcAlpha OneMinusSrcAlpha
Cull off
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 texcoord : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 pos : SV_POSITION;
};
sampler2D _MainTex;
float4 _MainTex_ST;
fixed4 _Color;
float _Magnitude;
float _Frequency;
float _InvWaveLength;
float _Speed;
v2f vert (appdata v)
{
v2f o;
float4 offset;
offset.yzw = float3(0,0,0);
offset.x = sin(_Frequency * _Time.y + v.vertex.x * _InvWaveLength + v.vertex.y * _InvWaveLength + v.vertex.z * _InvWaveLength) * _Magnitude;
o.pos = UnityObjectToClipPos(v.vertex + offset);
o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
o.uv += float2(0, _Time.y * _Speed);
return o;
}
fixed4 frag (v2f i) : SV_Target
{
fixed4 c = tex2D(_MainTex, i.uv);
c.rgb *= _Color.rgb;
return c;
}
ENDCG
}
}FallBack "VertexLit"
}

另一種頂點影片就是廣告牌技術,會根據視角方向來旋轉多邊形,看上去好像面向攝像頭,比如延誤云朵閃光,其中的難處在于建立三個相互垂直的基向量,視角方向和向上的向量往往不垂直,所以要通過叉乘得到一個與兩者相垂直的變數,然后再取該向量與視角方向叉積,更新向上的變數,

float3 center = float3(0,0,0); float3 viewer = mul(unity_WorldToObject, float4(_WorldSpaceCameraPos, 1)); float3 normalDir = viewer - center; normalDir.y = normalDir.y * _VerticalBillboarding; normalDir = normalize(normalDir); float3 upDir = abs(normalDir.y) > 0.999 ? float3(0, 0, 1) : float3 (0, 1, 0); float3 rightDir = normalize(cross(upDir, normalDir)); upDir = normalize(cross(normalDir, rightDir));
float3 centerOffs = v.vertex.xyz - center; float3 localPos = center + rightDir * centerOffs.x + upDir * centerOffs.y + normalDir * centerOffs.z; o.pos = UnityObjectToClipPos(float4(localPos, 1));
上面就是得到三個基向量的程序,_VerticalBillboarding主要是這個向量通過調整數值來改變normal變數來模擬特殊需求,比如草地下面的根部是不懂的,還有一些廣告牌只會有旋轉操作但是不會脫離垂直方向,
// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'
// Upgrade NOTE: replaced '_World2Object' with 'unity_WorldToObject'
Shader "Unlit/11-4Billboard"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_Color ("Color", Color) = (1,1,1,1)
_VerticalBillboarding ("VerticalBillboarding", Range(0, 1)) = 1
}
SubShader
{
Tags { "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" "DisableBatching"="True" }
Pass
{
Tags { "LightMode"="ForwardBase" }
ZWrite Off
Blend SrcAlpha OneMinusSrcAlpha
Cull off
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#include "Lighting.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 texcoord : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 pos : SV_POSITION;
};
sampler2D _MainTex;
float4 _MainTex_ST;
fixed4 _Color;
float _VerticalBillboarding;
v2f vert (appdata v)
{
v2f o;
float3 center = float3(0,0,0);
float3 viewer = mul(unity_WorldToObject, float4(_WorldSpaceCameraPos, 1));
float3 normalDir = viewer - center;
normalDir.y = normalDir.y * _VerticalBillboarding;
normalDir = normalize(normalDir);
float3 upDir = abs(normalDir.y) > 0.999 ? float3(0, 0, 1) : float3 (0, 1, 0);
float3 rightDir = normalize(cross(upDir, normalDir));
upDir = normalize(cross(normalDir, rightDir));
float3 centerOffs = v.vertex.xyz - center;
float3 localPos = center + rightDir * centerOffs.x + upDir * centerOffs.y + normalDir * centerOffs.z;
o.pos = UnityObjectToClipPos(float4(localPos, 1));
o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
return o;
}
fixed4 frag (v2f i) : SV_Target
{
fixed4 c = tex2D(_MainTex, i.uv);
c.rgb *= _Color.rgb;
return c;
}
ENDCG
}
}FallBack "Transparent/VertexLit"
}


然后可以看到我們在做河流的時候河流的影子是不對的,我們需要重寫ShaderCaster Pass,
struct v2f {
V2F_SHADOW_CASTER;
;
v2f vert(appdata_base v){
v2f o;
float4 offset;
offset.yzw = float3(0,0,0);
offset.x = sin(_Frequency * _Time.y + v.vertex.x * _InvWaveLength + v.vertex.y * _InvWaveLength + v.vertex.z * _InvWaveLength) * _Magnitude;
v.vertex += offset;
TRANSFER_SHADOW_CASTER_NORMALOFFSET(o);
return o;
}
fixed4 frag(v2f i) : SV_Target{
SHADOW_CASTER_FRAGMENT(i);
}
這里采用了UnityCG.cginc中定義的一些宏,來計算陰影所需的內容,V2F_SHADOW_CASTER用于定義一些變數,
Shader "Unlit/11-5VertexAnimWithShadow"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_Color ("Color", Color) = (1,1,1,1)
_Magnitude ("Distortion Magnitude", Float) = 1
_Frequency ("Distortion Frequency", Float) = 1
_InvWaveLength ("InvWaveLength", Float) = 10
_Speed ("Speed", Float) = 0.5
}
SubShader
{
Tags { "DisableBatching"="True" }
Pass
{
Tags { "LightMode"="ForwardBase" }
Cull off
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 texcoord : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 pos : SV_POSITION;
};
sampler2D _MainTex;
float4 _MainTex_ST;
fixed4 _Color;
float _Magnitude;
float _Frequency;
float _InvWaveLength;
float _Speed;
v2f vert (appdata v)
{
v2f o;
float4 offset;
offset.yzw = float3(0,0,0);
offset.x = sin(_Frequency * _Time.y + v.vertex.x * _InvWaveLength + v.vertex.y * _InvWaveLength + v.vertex.z * _InvWaveLength) * _Magnitude;
o.pos = UnityObjectToClipPos(v.vertex + offset);
o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
o.uv += float2(0, _Time.y * _Speed);
return o;
}
fixed4 frag (v2f i) : SV_Target
{
fixed4 c = tex2D(_MainTex, i.uv);
c.rgb *= _Color.rgb;
return c;
}
ENDCG
}
Pass{
Tags { "LightMode"="ShadowCaster" }
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_shadowcaster
#include "UnityCG.cginc"
float _Magnitude;
float _Frequency;
float _InvWaveLength;
float _Speed;
struct a2v {
float4 vertex : POSITION;
float4 texcoord : TEXCOORD0;
};
struct v2f {
V2F_SHADOW_CASTER;
};
v2f vert(appdata_base v){
v2f o;
float4 offset;
offset.yzw = float3(0,0,0);
offset.x = sin(_Frequency * _Time.y + v.vertex.x * _InvWaveLength + v.vertex.y * _InvWaveLength + v.vertex.z * _InvWaveLength) * _Magnitude;
v.vertex += offset;
TRANSFER_SHADOW_CASTER_NORMALOFFSET(o);
return o;
}
fixed4 frag(v2f i) : SV_Target{
SHADOW_CASTER_FRAGMENT(i);
}
ENDCG
}
}FallBack "VertexLit"
}

最后就是一些小事項,取消批處理可以放置模型空間出現問題,但是會帶來性能的問題,就是DrawCall增加了,所以應該避免一些在模型空間的計算,用頂點顏色存頂點到錨點的距離,避免使用模型空間中性作為錨點,
感謝你看到這里,Cheers!
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/50498.html
標籤:其他
上一篇:推桿電機電源選擇
