割と真面目にShaderを勉強している件
皆さんこんばんはぐっちーです。
ここ最近進捗も上げず記事も書かずだったのでさすがにと思い、最近UnityのShaderについて割と真面目に勉強している(←いつもそうしろ)ので学んだことについて書きたいと思います。
まず初めに今回私が勉強するにあたり参考にしている本は、Unity 2018 Shaders and Effects Cookbookというものです。
Shaderついての記事を探すとおすすめ書籍としてほぼ必ず出てくるので知っている方もいるんじゃないでしょうか。
こちらの本は洋書ですので内容すべてが英語です。それもあり英語が大の苦手な私も手を出せずにいたんですが大学の図書館に追加されたとのことで試しに借りてみたところ、辞書はほしいですが文法自体はやさしかったり、作業の流れは同じような書かれ方をするので一度読めればそれ以降も読めるといった感じで考えていたよりも読みやすかったです。なのでもし「英語は...」というような理由で敬遠している方も大丈夫です!
Unity 2018 Shaders and Effects Cookbook: Transform your game into a visually stunning masterpiece wi
では本編
この記事では主にChapter3の内容(簡単なサーフェスシェーダー)について書いていきたいと思います。同じ本で「読んでもわからんかった」という方やShaderを勉強してみたいという方の参考になったら幸いです。(全部に触れると長くなるのでいくつか割愛します)
サーフェスシェーダーの流れ
まずはサーフェスシェーダーについて説明します。サーフェスシェーダーはライティングや影を考慮したものを使用するときに使います。さっくりとした流れはこんな感じです。↓
3DモデルからUVなどの頂点情報をInput構造体というものに入れてSurf関数に渡してあげます。そしてSurf関数の中にどんなふうに描画するか書いてライティングに渡してあげます後はUnityがやってくれるのでshaderファイルを保存してUnityに戻りエラーがなければちゃんと描画されます!
Surf関数が渡す値は構造体で色や法線などの情報を持ちます。中身については公式のリファレンスを確認していただければと思います。
テクスチャを貼る
まずはシンプルにテクスチャを貼りましょう。UnityのProjectビューでCreate/StanderdSurfaceShaderを選択するとサーフェスシェーダーを作成できます。そして作ったShaderを右クリックし、Create/Materialをするとそのシェーダーが割り当てられたマテリアルが作成されます。できたマテリアルをテクスチャを貼りたいモデルにアタッチし、InspectorのAlbedoとある窓にテクスチャを入れるとテクスチャが張られるはずです。これくらいは特別Shaderを書かずともできるんですね。
ステンドグラスみたいなものを作る
ステンドグラス、つまり部分的に半透明なものを作ります。
まずは画像の用意ですが注意が必要で、Photoshopなどの画像ソフトで透明にしたい部分(ガラスの部分など)をレイヤーマスクなどで透明にしておいてください。透明にしたい部分を選択した状態で白のレイヤーマスクを作成し濃度を調整してあげるとできると思います。(この辺の動作がよくわかってないのでちゃんとしたやり方ご存じの方いましたら教えて下さい。とりあえず上記の方法ではうまくいきました)
それをUnityへもっていったら今度はShaderを書きます。著作権の関係上コードを全部乗せるわけにはいかない(自分が書いたコードがまんま一緒なので。)ので部分的にかいつまんで説明します。
この場合ではやることは3つです、
まず、_Grossiness、_Metaricの2つをPropertiesとInput構造体の下あたりから削除します(今回使わないので)
次にSubShaderの中にあるTagsの中を以下のように変更します。
Tags {
"Queue"="Transparent" //描画順を指定する。半透明を扱うときはTransparent
"RenderType"="Transparent" //ShaderReplacementで使う設定(よくわかってない)
}
後は、#pragma surface surf Standard fullforwardshadowsとある行のfullforwardshadowsをalpha:fadeに変更すればOKです。
描画順というのはそのままオブジェクトを描画する順番なのですがカメラから遠いものを先に描画します。描画順はレンダーキューというもので管理されていてQueueタグの設定値を変更することでそのマテリアルをアタッチしたオブジェクトの描画順を決定します。設定値については以下を参照してください。
テクスチャブレンド
テクスチャブレンドとは2個以上のテクスチャを混ぜることです。ただ混ぜるのではなくどんな割合でブレンドするか示したテクスチャ(マスク)が必要になります。マスクには白黒やカラーのノイズ画像が用いられることが多いです。これを使うと例えば土や石、草の混じった地面を作るときに自然と混ざった具合で作ることができます。もとからそのようなテクスチャを作ってもいいのですがパラメータをいじることで動的に具合を変更できるのでこっちのほうがおすすめです。
参考書ではRGBAそれぞれに1枚ずつテクスチャを割り当てる方法をとっていたのでそれについて説明します。白黒でやるものはちくわさんという方(Shader調べてるとたいてい出てくる有名な方)が記事になさっているのでそちらをおすすめします。
全部説明したいところですがこの時点でまあまあ長くなってきているので変数定義などは省略します。(_〇Textureが各チャンネルに対応したテクスチャが入ります。_MaskTexはマスクです)
float4 maskData = tex2D(_MaskTex, IN.uv_MaskTex);
tex2Dという関数は第1引数のテクスチャの、第2引数で指定したUV座標にある色を返してくれるものです。float4という型はfloat型を4つまとめたベクトルや配列みたいなものだと思ってくれてOKです。この処理を_〇Texture系にも同じようにやります。
次にそれの色を使って最終的に描画する色を決めていきます。
float4 outColor = lerp(rTexData, gTexData, maskData.g);
leap(a,b,p)はa,bを線形補間してくれる関数で割合はpです。pが0に近いと戻り値はaに近くなり1日かければbに近くなります。今回はまず赤と緑をブレンドします。ここでいう赤、緑というのはそれぞれのチャンネルに対応したテクスチャですのでテクスチャの色が真っ赤、真みどりというわけではなくピクセルの色をテクスチャRとテクスチャGの間で線形補完するということです。マスク画像の各ピクセルのgの値で補間を行っているのでテクスチャRとGを重ねたときにマスクで緑が強い部分はGのほうが強く出るといった感じです。同じ要領でテクスチャB、Aについてもやっていきます。ただし、Bをブレンドするときからは直前でブレンドしたものに対して補間を行うので第1引数はoutColorになります。outColorのアルファ値は1.0です。
後は全体に広がる拡散光の色の具合など設定するのですが土など色がついてるテクスチャの場合特別設定する必要はなさそうなので省略します。詳しくは参考書を見てください。
o.Albedo = outColor.rgb * _DiffuseColor;
o.Alpha = outColor.a;
最後に渡す用の構造体の要素に計算結果を代入することで出力完了です。
実際やってみるとこんな感じになります。Inspectorを見ると4種類のとマスク画像が入ってるのがわかります。Sceneに出てる地面はこれまでやってきた方法で作ったマテリアルからできています。(凸凹はもともと)
だいぶ長くなってしまいましたが特に紹介したかったのはこの辺です。
自分自身ふわっとした知識しかなかったのですがこの本を読んだことでかなりしっかりとまとまったように思えます。英語だからと引かないで読んでみてください!!
それでは今日はこの辺で(`・ω・´)