ShaderForgeでスペースハリアーもどき画面

Shaderはじめました

 XNAをやってた頃、一回だけシェーダーに挑戦した事があるのですが、当時はなんかもう手探りな上によくわからないままやってたのですが、最近は色々情報も入手しやすくなってシェーダーの技術資料を入手できたりと色々勉強する機会も増えてきました。ゲームの表現の幅も色々広がるのでこれはもうバンバン使い倒すのが吉でしょう。というわけで色々試行錯誤しながらシェーダーの記事書いてみたいと思います。

まずはこんな感じで

 昔8ビットパソコン時代の人たちなら一度は作ってみるこんな画面。あらかじめグラフィック画面に背景を描画してパレットアニメーションでスクロールしてるように見せるテクニックですが、こいつは一切プログラム書いてません。シェーダーのみで自動的にアニメーションしています。まずはこいつのシェーダーをご覧ください。

 シェーダーの作成には ShaderForge というアセットを使用しています。ノードベースでシェーダーを感覚的に作成する事ができるのでかなり重宝します。ノードだけで書くと面倒くさい部分は直接シェーダーコードを記述します。

 まずは左下のブロックを説明します。抹茶色のノードは「プロパティ」となり、Unity のマテリアルで設定できる値になります。ここではスライダー型とカラー型のプロパティをそれぞれ定義し、そのまま SET ノードで変数に突っ込んでいます。SET で変数に設定した値は GET ノードで取得できます。このシェーダでは特に SET / GET ノードを使う必要はなかったのですが、ノードを接続するラインが見づらくなるので見やすさの為に設定しています。

  • Slider
    • マテリアルのインスペクタに表示される項目になります。Min に最小値、Max に最大値を設定する事で指定範囲の数値を任意に設定できるようになります。
  • Color
    • マテリアルのインスペクタに表示される項目になります。任意のカラーを指定できます。ノードからは RGB だけでなく、R、G、B、A をそれぞれ個別に取り出す事ができます。
  • Set
    • 各種ノードの出力結果を変数に格納します。格納した変数の内容は Get ノードから取り出す事ができます。ShaderForge ではノード構成が複雑になって見づらくなる時に活用すると便利です。

 次は左上のブロックの説明をします。

  • Multiply
    • 2つ以上の入力値の掛け算の結果を返します。画面写真では入力は2つですが、別のノードの出力をドラッグする事で3つ目以降の入力が行えます。入力値はカラーだったりベクトルだったり単体の数値だったりなんでも入力できます。出力結果のフォーマットは入力値によって変化します。ベクトルや単体の数値との掛け算も可能です。
  • Add
    • 足し算を行います。基本的には Multiply と同じです。
  • Get
    • Set で登録した変数を取得します。
  • Time
    • タイマーの秒数が入ります。シェーダーの中でアニメーションさせるのにとても便利です。
  • UV Coord.
    • UV座標を生成します。具体的にはポリゴンのそれぞれのピクセルを描画する時に、該当ピクセルの U と V を得る事ができます。上記のノード構成では UV Coord. の値に Multiply や Add で変化を与えてますが、その事によってポリゴンに張り付けるテクスチャをスクロールさせたり拡大縮小させたりする事ができるようになります。テクスチャの設定が Repeat になってる場合、縮小をかける事で同じテクスチャパタンを繰り返し表示させる事もできるようになります。

 ここでは、UV 座標をスクロールさせるための処理が書かれています。Time ノードから得られる時間を UV 座標のそれぞれ U と V に加算しています。USpeed と VSpeed は Time に対して掛け算する事でそれぞれのスクロールスピードを調整します。最後に Get でえられた xmax と ymax の値を描けているのはテクスチャパタンの繰り返し数を増やしたり減らしたりする処理になります。

  • Code
    • シェーダー内に関数を定義します。残念ながら必ず出力が最終的に Main ノードにつながっている必要があり、何度も使いまわす便利関数を作るには工夫がいりそうな残念なノードでもあります。中に記述されているコードの説明は後述します。
  • Main
    • 概要
      • 最終的なカラーや質感を決定するためのノードです。ここの様々な入力に各種計算結果を接続する事でピクセルカラーや外観が決定されます。
    • Emission
      • ピクセルカラーを決定します。
    • Outline Width
      • ここに値を入力すると、モデルの輪郭線を表示するようになります。球体や単純な形状だとここに値を突っ込むだけでうまく表示されますが、輪郭線がおかしな事になっている場合は Geometry の Outline Extude Direction の値を変更する事で調整する事ができます。
        • From origin : オリジナルの形状を拡大し、ポリゴン面を反転させる事で輪郭を表示します。
        • Vertex normals : 法線ベクトルから輪郭線の表示を判断するっぽいです。デフォルト設定はこれです。
        • Vertex normals : 頂点カラーから輪郭線の表示を判断するっぽいです。

// x と y にスクロール値が入ってきますが、UV座標の最大値である
// 1 を超えているため、fmod 関数で 1 で割った余りを取得する事で
// クリッピングします。frac 関数でもよかったんじゃねか?
float valx = fmod(x, 1);
float valy = fmod(y, 1);

// 最終カラーを決定するための変数
int val = 0;

// 現在のU値が指定されたXBorderで指定された値より小さい場合、1ビット目を立てる
if (valx < xb ) val += 1;

// 現在のV値が指定されたYBorderで指定された値より小さい場合、2ビット目を立てる
if (valy < yb ) val += 2;

// val に設定された値で最終カラーを決定する
if (val == 1) return c1;
if (val == 2) return c2;
if (val == 3) return c3;

// どのビットも絶たなかった場合、デフォルトカラーを返す
return c0;

疲れた

 普通にPC上でシェーダを作って楽しむ分には何も問題は無かったりしますが、これが WebGL や iPhone、Android 等に組み込む場合色々と問題が出てきます。PC上ではちゃんと動くのに他のプラットフォームでは真っ黒だったりと結構面倒でした。それ以上に今回の記事書くのが久しぶりすぎてめちゃ時間かかりました。次回以降はもっとサクサク書けるようになりたいなっと。ではまた。

参考

ツイートツイート