頂点シェーダーアニメーション入門
◆ 目次
◆ 関連リンク
◆ 頂点シェーダーとは
◆ 頂点の動かし方
◆ モデル変換行列
◆ 関連リンク
今回の教材
関連ページ
◆ 頂点シェーダーとは
以下のコードはシンプルなUnlit Shader
頂点シェーダに関係するのはappdataとvert
今回はvertにてMVP変換を行う前に、ローカル座標(モデル座標)の頂点を動かすことでアニメーション処理を行う
code:shader.cs
Shader "Unlit/Sample"
{
struct appdata // 入力される頂点情報
{
float4 vertex : POSITION; // 頂点情報(モデル空間)
float2 uv : TEXCOORD0; // テクスチャUV
};
struct v2f // Vertex to Fragment
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};
sampler2D _MainTex;
float4 _MainTex_ST;
v2f vert (appdata v) // 頂点シェーダー
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex); // MVP行列=モデル・ビュー・プロジェクション行列
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
return o;
}
fixed4 frag (v2f i) : SV_Target
{
fixed4 col = tex2D(_MainTex, i.uv);
return col;
}
}
◆ 頂点の動かし方
頂点座標に_Positionプロパティで指定した値分だけ足す
code:shader.cs
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_Position ("Position", Vector) = (0,0,0,0)
}
float3 _Position;
v2f vert (appdata v)
{
v.vertex.xyz += _Position;
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
return o;
}
https://gyazo.com/1497f5ff9f48d1f57ec1c16ef23be715
プラスする数値を時間でずらしてみる
code:shader.cs
v2f vert (appdata v)
{
float4 offs = sin(_Time.y * 10 + v.vertex.y * 200) * _Distance;
v.vertex.x += offs;
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
return o;
}
https://gyazo.com/d58a06a453edc08fa8018471dae7f67e
◆ モデル変換行列
▼ 変換行列参考
▼ 行列計算復習
https://gyazo.com/379e9b4c3fd7e80d59c9e16f6f5c8c04
https://gyazo.com/5c1daabd1f43cff5223a3ea980c56759
▼ 平行移動
https://gyazo.com/35a4e1f60cfb5dbdaadc80d7f98c620a
code:shader.cs
v2f vert (appdata v)
{
float4x4 translateMat = float4x4
(
float4(1, 0, 0, _Position.x),
float4(0, 1, 0, _Position.y),
float4(0, 0, 1, _Position.z),
float4(0, 0, 0, 1)
);
v.vertex = mul(translateMat, v.vertex);
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
return o;
}
▼ 拡大縮小
https://gyazo.com/b17d9b07c25bc0c21e3177e289e067b3
code:shader.cs
v2f vert (appdata v)
{
float4x4 translateMat = float4x4
(
float4(_Position.x, 0, 0, 0),
float4(0, _Position.y, 0, 0),
float4(0, 0, _Position.z, 0),
float4(0, 0, 0, 1)
);
v.vertex = mul(translateMat, v.vertex);
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
return o;
}
アニメーションさせてみる
code:shader.cs
v2f vert (appdata v)
{
float4x4 translateMat = float4x4
(
float4(_Position.x+abs(sin(_Time.y*3))*0.1, 0, 0, 0),
float4(0, _Position.y+abs(sin(_Time.y*3))*0.1, 0, 0),
float4(0, 0, _Position.z, 0),
float4(0, 0, 0, 1)
);
v.vertex = mul(translateMat, v.vertex);
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
return o;
}
TweenでScaleを動かしてるような動きを作れた
https://gyazo.com/ebc321f547d07b03a675efa1a163eb0c
Porin.iconシェーダーは他ファイルからのインポートもできるみたいなので、シェーダー用Easing Functionをつくるといいかも?
▼ 回転
https://gyazo.com/45ddf4c48495036f53b0f0cc19bda573
code:shader.cs
v2f vert (appdata v)
{
// z軸中心に回転
// Inspectorで入力した数値を使用するためにdegreeからradianへの変換処理を入れる
float sinA = sin(radians(_Rotation.z));
float cosA = cos(radians(_Rotation.z));
float4x4 translateMat = float4x4
(
float4(cosA, -sinA, 0, 0),
float4(sinA, cosA, 0, 0),
float4(0, 0, 1, 0),
float4(0, 0, 0, 1)
);
v.vertex = mul(translateMat, v.vertex);
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
return o;
}
入力した値zと-zの間で振り子のように揺れるようにする
code:shader.cs
v2f vert (appdata v)
{
float sinA = sin(radians(sin(_Time.y*5) * _Rotation.z));
float cosA = cos(radians(sin(_Time.y*5) *_Rotation.z));
float4x4 translateMat = float4x4
(
float4(cosA, -sinA, 0, 0),
float4(sinA, cosA, 0, 0),
float4(0, 0, 1, 0),
float4(0, 0, 0, 1)
);
v.vertex = mul(translateMat, v.vertex);
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
return o;
}
https://gyazo.com/70416800f2582fda023390d3d38ab37c
▼ 拡大縮小→回転→移動の順番
順番は大事
この順番を変えると違う動きになる
code:shader.cs
v2f vert (appdata v)
{
// スケール
float4x4 sizeMat = float4x4
(
float4(_Scale.x+abs(sin(_Time.y*5))*0.3, 0, 0, 0),
float4(0, _Scale.y+abs(sin(_Time.y*5))*0.3, 0, 0),
float4(0, 0, _Scale.z, 0),
float4(0, 0, 0, 1)
);
v.vertex = mul(sizeMat, v.vertex);
// Z軸回転
float sinA = sin(radians(sin(_Time.y*5) * _Rotation.z));
float cosA = cos(radians(sin(_Time.y*5) *_Rotation.z));
float4x4 rotMat = float4x4
(
float4(cosA, -sinA, 0, 0),
float4(sinA, cosA, 0, 0),
float4(0, 0, 1, 0),
float4(0, 0, 0, 1)
);
v.vertex = mul(rotMat, v.vertex);
// 平行移動
float4x4 translateMat = float4x4
(
float4(1, 0, 0, _Position.x),
float4(0, 1, 0, _Position.y),
float4(0, 0, 1, _Position.z),
float4(0, 0, 0, 1)
);
v.vertex = mul(translateMat, v.vertex);
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
return o;
}
https://gyazo.com/1b4d3459520228c10247e2bd4d2f125b