今回は、教師がコース内でコード画像や技術的な指示を与えなかったため、ノートに最終的な効果が直接表示されます。
- 下図の左側はフレームシーケンスアニメーション(wisps)、右側は極座標です。
フレームシーケンスアニメーション
フレーム シーケンスの原理は、規則的な行と列にソートされた一連のフレーム テクスチャをサンプリングすることです。時間の変化に応じて、表示されるテクスチャの内容は異なります。シーケンス フレーム テクスチャは次のとおりです。
- 一連の写真を通常のサイズで並べて見ることができます。
私たちの原則は次のとおりです。
- まず、画像全体の UV 座標は主に黄色の座標系に基づいており、原点は画像全体の左下隅にあります。
- それぞれの小さな画像を取得するには、このテクスチャをカットし、各小さな画像を均等に分割して、後で小さな画像を切り替えることができるようにする必要があります。
- 大きな UV を小さな画像 UV に変換する必要があります。したがって、大きな UV の値の範囲は [0,1] であるため、行と列の数を 1 で割ります。また、1 を行と列の数で割って、小さな画像ごとの UV の値の範囲を取得します。U の値は [0, 1/列数] になり、V の値は [0,,1/行数] になります。
- 上記の手順で取得した UV は左下隅の小さな画像の UV になりますが、UV 座標の原点は依然として左下隅であることに注意してください。
- ただし、必要なのは左から右、上から下の順序であるため、UV 原点を最初の行と最初の列の位置に移動する必要があります。
- UV 座標を移動した後、次の画像を切り替えるために必要なアルゴリズムは 1 つだけです。詳細については、私のコードを参照してください。
- アニメーションはシェルのようにモデルの外側に設定されているため、シェルのような効果を作成するには、モデルの頂点法線を法線方向に沿って外側に一定距離オフセットする必要があります。
- フレーム シーケンス アニメーションはシェル上で実行されるため、2 番目のパスで処理する必要があるため、シェーダーのこの部分ではダブル パスが使用されます。
- 最初のパスは、AB メソッドを使用して、メイン テクスチャを通常どおりサンプリングすることです。
- 2 番目のパスでは、法線を使用して、AD メソッドを使用してフレーム シーケンス アニメーションを処理します。
コード
Shader "shader forge/L18_FireSequence"
{
Properties
{
_MainTex ("Base Color With A", 2D) = "white" {
}
_Opacity ("Opacity", Range(0.0,1.0)) = 0.5
_Sequence ("Sequence Texture",2D) = "gray" {
} //帧序列图
_RowCount ("Row",Int) = 3 //行数
_ColCount ("Col",Int) = 4 //列数
//_SeqID ("Sequence ID",Int) = 0 //帧序列号
_Speed ("Speed", Range(-10,10)) = 3
}
SubShader
{
//主要做的
Tags {
"Queue"="Transparent"
"RenderType" = "Transparent"
"ForceNoShadowCasting" = "True"
"IgnoreProjector" = "True"
}
Pass
{
NAME "FORWARD_AB"
Tags{
"LightMode" = "ForwardBase"
}
Blend One OneMinusSrcAlpha //AB
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
// make fog work
#pragma multi_compile_fog
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv0 : TEXCOORD0;
};
struct v2f
{
float2 uv0 : TEXCOORD0;
float4 vertex : SV_POSITION;
};
uniform sampler2D _MainTex;
uniform float4 _MainTex_ST; //我们的贴图偏移选项
uniform float _Opacity;
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv0 = TRANSFORM_TEX(v.uv0, _MainTex); //加上贴图偏移
return o;
}
fixed4 frag (v2f i) : SV_Target
{
fixed4 var_MainTex = tex2D(_MainTex, i.uv0);
float3 finalRGB = var_MainTex.rgb;
half opacity = var_MainTex.a * _Opacity;
return float4(finalRGB * opacity, opacity);
}
ENDCG
}
Pass
{
NAME "FORWARD_AD"
Tags{
"LightMode" = "ForwardBase"
}
Blend One One
//Cull Front
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
// make fog work
#pragma multi_compile_fog
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float4 normal:NORMAL;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 pos : SV_POSITION;
};
uniform sampler2D _Sequence;
uniform float4 _Sequence_ST; //我们的贴图偏移选项
uniform half _RowCount; //行数
uniform half _ColCount; //列数
//uniform half _SeqID; //帧序列号
uniform half _Speed;
v2f vert (appdata v)
{
v2f o;
//因为第二个pass是用来处理帧序列动画的,这个动画就像是壳子一样套在原模型的外面一层,所以需要让这个pass的模型顶点位置沿着法线方向增加一定的距离
v.vertex.xyz += v.normal * 0.003;
o.pos = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv,_Sequence); //为了能让它支持Tiling和offset
half seqID = floor(_Time.z * _Speed); //根据时间来取序列号
half rowID = floor(seqID / _ColCount); //根据_SeqID算出行号
half ColID = seqID % _ColCount; //根据_SeqID算出列号
half stepU = 1.0 / _ColCount; //计算每次移动的U值偏移,因为UV坐标的范围都为[0,1]
half stepV = 1.0 / _RowCount; //计算每次移动的V值偏移,因为UV坐标的范围都为[0,1]
half2 initUV = o.uv * float2(stepU,stepV); //将uv从范围[0,1]缩放为[stepU,stepV]
//因为默认uv坐标从左下角开始,我们要做一下缩放,将缩放成单个序列帧uv大小
initUV += float2(0.0, stepV * (_RowCount - 1));
//然后做偏移,将图片uv坐标的原点移动到第一个序列帧的uv坐标原点上
o.uv = initUV + float2(stepU * ColID, -stepV * rowID);
return o;
}
fixed4 frag (v2f i) : SV_Target
{
// sample the texture
fixed4 var_Sequence = tex2D(_Sequence, i.uv);
fixed3 finalRGB = var_Sequence.rgb;
fixed opacity = var_Sequence.a;
return fixed4(finalRGB * opacity, opacity);
}
ENDCG
}
}
}
最終効果
極座標
極座標部分も UV 座標の計算を実行しますが、UV 座標の代わりに角度と長さを使用します。
以下に示すように:
- まず、このテクスチャの UV 座標は、このテクスチャの左下隅を原点とする緑色の座標系です。
- UV 座標を赤色の座標系に移動したいのですが、UV の値の範囲も [0,1] から [-0.5,0.5] に変更され、座標系の原点が画像の中心になります。
- そして、そのUV座標値に基づいて、画像上のある点の角度θと原点からの長さを計算します。
- 角度 θ は角度であるため、値の範囲は [-pi,pi] となるため、その値の範囲を0,1に変更する必要があります。
- 原点から探している距離を取得し、それに変化部分を追加します(アニメーション用)
- 次に、その角度と長さを新しい UV として使用してテクスチャをサンプリングすると、極座標アニメーションを取得できます。
コード
Shader "shader forge/L18_PolarCoord"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {
}
_Opacity ("Opacity",Range(0,1)) = 0.5
_Color ("Color",Color) = (1.0,1.0,1.0,1.0)
}
SubShader
{
Tags {
"RenderType"="Opaque" }
LOD 100
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
UNITY_FOG_COORDS(1)
float4 vertex : SV_POSITION;
};
uniform sampler2D _MainTex;
uniform half _Opacity;
uniform half4 _Color;
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = v.uv;
return o;
}
fixed4 frag (v2f i) : SV_Target
{
i.uv -= float2(0.5,0.5);
half theta = atan2(i.uv.y,i.uv.x); //获得uv坐标的夹角
theta = theta / 3.1415926 * 0.5 + 0.5; //将夹角取值范围从(-pi,pi)转换到[-1,1]在转换到[0,1]
half dist = length(i.uv) + frac(_Time.x * 3);
i.uv = float2(theta, dist);
half4 var_MainTex = tex2D(_MainTex,i.uv);
half3 finalRGB = var_MainTex.rgb;
half opacity = var_MainTex.a * _Opacity;
//Alpha 通道是为保存选择区域而专门设计的通道,所以第四个值取1或者0或任意值都没什么变化
return float4(finalRGB * opacity,opacity); //真正让图片变透明的不是Alpha 实际是Alpha所代表的数值和其他数值做了一次运算
}
ENDCG
}
}
}
最終効果
頂点カラー
ここで、先生が教えてくださった極座標アニメーションのモデルは、あらかじめモデリングソフトで加工してあるのですが、パッチの周囲の円と中心がすべて黒くなっているので、パッチ上で再生すると極座標アニメーションがフェードイン、フェードアウトする効果が得られます。