シェーダでトランジション(図形)

シェーダでトランジション(図形)

外周から回るトランジション

 長方形を利用して外側から内側へ回りながら画面を黒くするシェーダを作成しました。

shader

 作成したシェーダは以下の通りです。

 uv座標(0~1)を(-1~1)へ変更し、これに分割数(div)を掛けることにより-分割数~分割数とします。

高さと幅が2となる長方形を作成します。画像に示すように正方形にはならず、アスペクト比に応じた長方形が表示されます。

下画像のように、長方形の下部が画面下、長方形の横半分が表示される座標へ移動させます。

長方形の大きさをfloat2(-1.0, 0.0)とし、幅を0とします。画像に示すように長方形はなくなります。

この長方形の横幅をインスペクタから変更できるようにします。

valを0から徐々に大きくすると

このように、長方形により下側を黒くすることができます。次に右側を作成します。長方形の中心位置を下画像の場所とします。

このままでは、下側の長方形と右側の長方形が同時に変化してしまいます。下側の長方形が画面端まで大きくなった後に、右側の長方形を大きくし始めたいので、下側の長方形が画面端に到達する大きさ(div*2)を右側の長方形の大きさから引きます。

さらに、上側と左側の長方形を作成します。

これを実行すると

このように外周を回りながら黒くすることができました。

次に二周目の長方形を作成します。一週目の全ての長方形の長さは(div * 2.0 – 2.0) * 4.0となります。そのため、長方形の大きさから(div * 2.0 – 2.0) * 4.0を減算しています。

以上より任意の周回(t)におけるコードは以下のようになります。場合によっては長方形の隙間が生じます。これを回避するため、mnによって長方形の幅を少し大きくしています。

この関数をfor文によって0~分割数の半分まで実行することで、長方形が周回しながら画面を覆うようになります。

 次に回転方向を変更できるようにします。x座標を反転させれば回転方向を逆にできます。よって

とすると、インスペクタのRotetion Directionへチェックを入れることで回転方向を変更できます。さらに、開始位置を座標を回転することで変更できるようにしました。

そして、アスペクト比で調整することで長方形から正方形へと変更します。これにより、Rotationが0、90、180及び270以外の値でもきれいに表示されるようになります。ただ、下画像のように、黒く塗りつぶす領域が画面より小さくなってしまいます。

そのため、座標を縮小することでこれに対応できるようにしています。

最後に、_Valueの値の範囲が0~1となるように

としています。高さ2の長方形で2*div+2*divの面積を埋めるため、このような式となっています。

実行結果

 以上のシェーダをUIのPanel上で実行すると以下の結果が得られます。外側から内側へぐるぐると回りながら黒く塗りつぶしています。

Division Size=16、Rotation=45、Size=0.6、Aspect Ratioにチェックを入れると以下のような結果が得られます。

複数の図形を使用

 前回の記事で同じ種類の図形を複数表示する方法を紹介しました。これを利用して、トランジション用のシェーダを作成しました。

画面端から円が拡がるトランジション

ある方向から直線的に円の大きさが変化するトランジションシェーダを作成しました。

shader

 作成したシェーダは以下の通りです。

 最初に、円を中心に表示させます。図形の描画についてはここに記述しています。lengthを用いて円を描画していましたが、今回は内積によって円の描画をしています。

表示する円の数(_Div)を決定します。縦方向の円の数はアスペクト比に応じて変化するようにしています。これにより、円がアスペクト比に応じて変形することを防いでいます。この円の数をuv座標に掛けると円を複数表示できます。

円を任意の大きさへ変更できるようにします。

円が大きくなるタイミングを座標を用いてずらします。座標stの整数部分を求めると図形ごとに座標に応じた整数値 (i_st) が得られます。これを利用して円が大きくなるタイミングをずらします。また、この値に定数(_Width)を掛けることでタイミングを調整することができます。Value=3、Width=0.3のとき下画像のような結果が得られます。

上記のコードでは左から右に円が大きくなっていきます。次は円が大きくなっていく方向を変更できるようにコードを変えます。円が大きくなる方向はベクトル(_Dir)を用いて決定します。まずは、このベクトルを正規化します。signによってベクトルの符号を取り出し、これを利用することによりベクトルの要素がマイナスの時、i_stを逆順(f)にしています。この値(f)と方向を表すベクトルの絶対値の内積によって求まる値で、円ごとに大きくなるタイミングを調整しています。

問題が一つあります。円は区切られた領域より大きくなることができません。そのため、円が領域からはみ出した部分は描画されません。

この問題を解決するために、自身の領域の円だけではなく自身と周りの9か所の領域における円を計算し、その円を全て描画するようにしました。これにより、自身の領域にはみ出してきた円を描画できるようになります。

さらに、 最後の円が大きくなり始めるタイミングに円が分割した領域より大きくなる値(2.0)を加算し、valに掛けることで_Valが0~1の範囲となるようにしています。

最後に、円を透明でなく黒く、つまり、反転させて表示できるようにコードを変更しました。

実行結果

 Division Size = 16、Width = 0.35、Direction(X, Y) = (1, 0)でシェーダを実行した結果は以下の通りです。

同じ条件でInverseにチェックを入れると以下のようになります。

また、Direction(X, Y) = (4, 3)とすると

このように、斜めに動きます。

中央から円が拡がるトランジション

 中央から拡がるように円の大きさが変化するトランジションシェーダを作成しました。

shader

 作成したシェーダは以下の通りです。

uv座標に分割数(_Div)を乗算するのは先ほどのシェーダと同様です。分割数が奇数の場合は最初の円が中央に配置されますが、偶数の場合は分割した領域の半分だけずれてしまいます。そのため、二項目を加算しています。分割数が8の時、stは0.5~8.5となります。

次に、縦方向の座標をアスペクト比で調整します。分割数が8、アスペクト比が4:3の時、st.y = 0.375~6.375となります。

ただ、座標にアスペクト比を乗算しただけでは最初の円を画面中央に配置できません。以下の画像は上記コードで区切った座標を可視化したものです。

そこで、以下の値を加算することで円を画面中央に配置できるようにしました。分割数8の時st.yは1.5~7.5となります。よって、i_st.yは-3~3となります。

また、先ほどのシェーダと同様に、円が領域からはみ出しても問題がないように処理をしています。i_stは中央を0とし縦(-x~x)と横(-y~y)の整数値となります。よって、lengthによってタイミングをずらすと、中央から拡がるようにそれぞれの円が大きくなります。

さらに、_Valが0~1の範囲に収まるよう処理を加えています。

このシェーダにも先ほどと同様に反転させる処理を加えています。

実行結果

 Division SIze = 16でシェーダを実行すると以下の結果が得られます。

また、Inverseにチェックを入れ、実行すると

となります。