Unity シェーダーチュートリアル 基本とサーフェースシェーダー
シェーダー
コンテンツを作る上でシェーダーを自作できると表現の幅がかなり広がります。
Unity には ShaderLab という初心者でも比較的簡単に記述できる仕組みが用意されていて、
ゴリゴリの Cg/HLSL を理解せずともシェーダーを作ることができます。
本ブログ では社内メモも兼ねて、初めての方にもできるだけ解りやすく、
見ていて疲れないように、決まり文句や難しい部分はさっさとおまじないで済ませつつ、
シェーダーチュートリアルを書いていこうと思います。(…自分が解ってないだけ)
シェーダーの新規作成
Unity のシェーダーにはいくつか種類がありますが、
本ブログでは「サーフェースシェーダー」と「頂点・フラグメントシェーダー」について書いていきます。
◆ サーフェースシェーダー
ライトやシャドウの影響を受けるシェーダー。
Standard Surface Shader で作成します。
Unity 5.4 以降は Standard Surface Shader (Instanced) という項目が増えています。
これはサーフェースシェーダーにパフォーマンス最適化機能を与えたもので、
後日書きたいと思います。
◆ 頂点・フラグメントシェーダー
ライトやシャドウの影響を受けないシェーダー。UI やエフェクトなどで使用します。
Unlit Shader で作成します。
今回は通常のサーフェースシェーダーについて説明していきます。
Standard Surface Shader を適当な名前で新規作成しましょう。
構造
作成したシェーダーを開いて見ると、以下のようなコードが自動生成されています。
順番に見ていきましょう。(投稿時の Unity のバージョンは 5.4.3f1 です)
まず、全体が Shader{} で囲まれています。
Shader "グループ名/シェーダー名" {
・・・・・・・・・・
}
「グループ名/シェーダー名」は、初期設定で「Custom/ファイルの名前」になっていますが、
自由に変更する事ができます。グループ名は / で区切って複数記述すると階層を付けられます。
解り易い整理された名前にしましょう。
その中の一番最初に Propaties{} があります。
Propaties {
プロパティ変数名 ("インスペクター表示名", 変数の型) = 初期値
}
ここで宣言したものがインスペクターに表示され、
色・テクスチャー・透明度・反射率など、質感のパラメーターとして利用できます。
試しにマテリアルを新規作成して、先ほど作成したシェーダーを充てて見てください。
インスペクターに上記コードの4つのプロパティが表示されているはずです。
その次に SubShader{} があります。
SubShader{
・・・・・・・・・・
}
ここが一番重要です。宣言したプロパティ達をどのように利用して描画するのかを
実際に記述する箇所になります。
最後に Fallback です。
FallBack "すべり止めシェーダー名"
「すべり止め」とは何か? 例えば以下の場合です。
SubShader{} にハイエンドPC向けのゴリゴリシェーダーを記述したとします。
PCでは当然描画されますが、モバイル端末で表示させた場合はどうでしょう?
ゴリゴリすぎて対応しておらず描画できません。
そんな時の回避策として、Fallback に指定されたシェーダーを呼び出して描画します。
ざっくりと、こんな構造になっています。それでは一つ一つを詳しく見ていきましょう。
その前に、上記コードが少し見づらいので俺様整形しました。
Propaties
プロパティ変数名 ("インスペクター表示名", 変数の型) = 初期値
プロパティ変数は自由に命名することができます。
ただし、Unityのデフォルトでアンダースコアと大文字から始めるようになっているので、
それに倣いましょう。
インスペクター表示名も自由に設定可能です。作業する人が解り易いように付けましょう。
変数の型にはいくつか種類があるので、適切なものを選びましょう。
また、初期値も型に合わせて設定します。
◆ Range(min, max)
範囲制限付きの数値をスライダーで設定できます。
基本的には、0~1の値を設定させたい時に使用されることが多いです。
初期値には、範囲内の適当な数値を設定します。
◆ Float
単純に数値を設定できます。
Range と Float は表示のされ方が違うだけで、中身は同じです。
私の場合、1以上の値が設定されるプロパティは Float にしています。 (例えば Intensity とか)
初期値も Range と同じく、適当な数値を設定します。
◆ Color
カラーピッカーから色を設定できます。
初期値には、(1, 1, 1, 1) のように、4つの数値を指定します。
右から (R, G, B, A) という意味です。
当然、(0, 0, 0, 1) でも (0.5, 0.1, 0.7, 0.4) でも、何でも構いません。
ただし、(255, 255, 255, 255) などとはしないでください。
◆ Vector
4つの数値を設定できます。
Color と Vector も表示のされ方が違うだけで、中身は同じです。
表示上は カラーピッカー(R, G, B, A) や (X, Y, Z, W) となっていますが、つまりは4つの数値です。
例えばの話、上記シェーダーコードの Color の型を Vector に差し替えても、問題ありません。
初期値も Color と同じく (1, 1, 1, 1) のように、4つの数値を指定します。
◆ 2D
テクスチャを設定できます。
初期値には、"white"{} もしくは "black"{} を設定します。
テクスチャが充てられていない時にどのように表示されるか、という指定です。
◆ Cube
キューブマップを設定できます。
初期値には、"white"{} もしくは "black"{} を設定します。
Unity5 でリフレクションプローブが実装されてから、活躍の場が減りました。
これらの型を適切に使い分けて、美しいインスペクターを目指しましょう。
例として、最悪に作業しづらいシェーダーを作ってみました。
分かりますでしょうか?
Color R の X、Color G の Y、Color B の Z, Color A の W を色に指定しています。
この様に Color 一発で済ませれば良いものを、すべて Vector しかも要素ごとに分けてみました。
Range も Float も Color も Vector も結局は数値なので、どんな使い方もできてしまう訳です。
SubShader
Tags
Tags {
"Key n" = "Value n"
}
ここは Replaced Shader 云々とちょっとややこしいのですが、
正しく設定しないと、描画がおかしくなったりします。
が、とりあえず難しいことは考えず、以下のようにしておけば概ね問題ないでしょう。
◆ 不透明シェーダーの場合
Tags {
"Queue" = "Geometry"
"RenderType" = "Opaque"
}
◆ 透明シェーダーの場合
Tags {
"Queue" = "Transparent"
"RenderType" = "Transparent"
}
◆ アルファテストシェーダーの場合(葉っぱとか、アルファでクリッピングするやつ)
Tags {
"Queue" = "AlphaTest"
"RenderType" = "TransparentCutout"
}
シェーダーLOD
LOD 数値
シェーダーLODは、強制的に描画レベルを落としたい時などに使うのですが、
今は使わないのでとりあえずこのままにしておいてください。後日書こうと思います。
CGPROGRAM ~ ENDCG
CGPROGRAM
・・・・・・・・・・
ENDCG
ここからが本番です。この CGPROGRAM ~ ENDCG の中に、描画処理を記述していきます。
上から順番に見ていきましょう。
#pragma target シェーダーモデル
シェーダーモデルによって、使えるテクスチャの数や機能が違います。単純に、高い方が色々できます。
テッセレーションなど、DirectX 11 の機能を使いたい場合は、5.0 にする必要がありますが、
とりあえずデフォルトの 3.0 にしておきましょう。
#pragma surface 関数名 ライティングモデル オプション
これが、「サーフェースシェーダーを使いますよ」という設定です。
関数名は自由に決めることができます。(デフォルトは surf)
ちょっと下の行を見るとこんな記述がありますね。
void surf (Input IN, inout SurfaceOutputStandard o) {
・・・・・・・・・・
}
ここにも surf と書いてあります。
つまり、#pragma surface で関数を宣言して、 void surf で中身を書く、という事になるので、
関数名を変更した時は、両方同じ名前にする必要があります。
まぁ、変更せずにそのまま surf で良いでしょう。
ライティングモデルでは、どのように光の反射を計算するかを指定します。
Unity4 までは Lambert や BlinnPhong がメインでしたが、
Unity5 からは Standard を基本的には使う事になります。
ライティングモデルを自作して使うこともできます。(相当な知識が必要)
◆ Standard
Unity5 で追加された物理ベースライティングモデル。
◆ Lambert
100%拡散反射モデル。
ライトを当ててもスペキュラ(光源の強い反射)がでません。
リフレクションプローブが適用されません。
◆ BlinnPhong
スペキュラライティングモデル。
パラメーターでスペキュラ(光源の強い反射)を調節できます。
リフレクションプローブが適用されません。
オプションには色々あるのですが、以下がよく使われます。
複数を使いたい場合は半角スペースを空けて続けて記述します。
◆ fullforwardshadows
フォワードレンダリングで、ポイントライトやスポットライトを使いたい場合に必要です。
◆ alpha
透明シェーダーにしたい場合に必要です。
◆ alphatest:_Cutoff
アルファテストシェーダーにしたい場合に必要です。
_Cutoff は Properties{} で Float もしくは Range で宣言する必要があります。
変数宣言
Properties{} で宣言したプロパティを使えるようにするため、ここでも変数として宣言します。
ただし、Properties{} では Range、Float、Vector、Color、2D、Cube という型でしたが、
ここでは違う型になります。
◆ 数値の型(Range、Float、Vector、Color)
float、half、fixed の3種類があります。
3つの違いは数値の精度で、float が最も高く、 fixed が最も低いです。
使い分け方は、とりあえず Unity のデフォルトに従い、
ワールド空間とテクスチャの座標は float、色は fixed、それ以外を half にすれば良いでしょう。
また、含まれる数値が2つ以上の場合は、float2、float3、float4 と後ろに数字をつけます。
例えば Color は RGBA の4つの数値を持っているので fixed4 ですね。
◆ テクスチャの型(2D)
sampler2D
◆ キューブマップの型(Cube)
samplerCUBE
入力構造体
struct Input {
・・・・・・・・・・
};
ここで、UVや頂点カラーなど surf に渡して使いたい情報を定義します。
UVの定義の仕方を見てみましょう。
float2 uv_MainTex;
前の項目に書いてあり通り、テクスチャ座標なので float2 で定義します。
(u と v の2次元座標なので float2)
そして見て分かる通り、uv のあとに Properties {} で宣言したテクスチャの変数名である、
_MainTex を続けて記述します。
これでテクスチャを貼り付けるためのUVが使用できるようになります。
渡せる情報はUVの他にも色々あるので、後日書いていこうと思います。
surf 関数
void surf (Input IN, inout SurfaceOutputStandard o) {
・・・・・・・・・・
}
プロパティの変数(_Colorとか)や入力構造体から渡ってきた情報(UVとか)を利用して、
あれこれ計算させたあとに、SurfaceOutputStandard に接続して完了です。
SurfaceOutputStandard とは何かと言うと DCCツールや UE4 を使っている方は
分かりやすいと思います。マテリアルの編集画面で最終的な接続先となるアレです。
Unity5 の Standard では以下のように項目が用意されています。
struct SurfaceOutputStandard {
fixed3 Albedo; // 色(RGB) デフォルトは黒
fixed3 Normal; // 法線(XYZ) デフォルトは設定なし
half3 Emission; // 自己発光(RGB) デフォルトは黒 HDRにもなるから fixed じゃなくて half なのかな
half Metallic; // 金属かどうか(0 ~ 1) デフォルトは0
half Smoothness; // ツルツル度合い(0 ~ 1) デフォルトは0
half Occlusion; // オクルージョン・遮蔽 以外の言葉が思いつかない(0 ~ 1) デフォルトは1(0が完全遮蔽)
fixed Alpha; // 不透明度(0 ~ 1) デフォルトは0
};
サンプルコードを見てみましょう。
void surf (Input IN, inout SurfaceOutputStandard o) {
fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
o.Albedo = c.rgb;
o.Metallic = _Metallic;
o.Smoothness = _Glossiness;
o.Alpha = c.a;
}
tex2D(テクスチャ変数名, UV);
テクスチャを使用するには、tex2D という関数を呼び出します。
_MainTex はもう見慣れましたね。UV 部分に注目してください。IN. という記述があります。
surf のところにも、 Input IN と書いてありますね。
入力構造体から渡ってきた情報を IN という名前で読み込んでいるわけです。
なので、例えば以下のように IN じゃなくても問題ありません。
void surf (Input InputDayo, inout SurfaceOutputStandard o) {
fixed4 c = tex2D (_MainTex, InputDayo.uv_MainTex) * _Color;
・・・・・・・・・・
}
まぁ、わざわざ変える意味はないですね。そのまま IN でいきましょう。
最初の一行目は、_MainTex と _Color を掛け合わせてc という変数に代入しています。(色なのでfixed4)
つまり、テクスチャの全体的な明るさや色をインスペクターで即時的に調整したいわけですね。
もし、_Color の掛け合わせがなければ、納得がいく色になるまで、
Unity と Photoshop なりを行ったり来たりと面倒な事になります。
その後、色の最終接続である Albedo に c の RGB を代入しています。
o.Albedo という記述になっていますね。これも先程の IN と同じような事です。
最終的な接続である SurfaceOutputStandard を o という名前で書き出しています。
void surf (Input IN, inout SurfaceOutputStandard o) {
・・・・・・・・・・
}
その他、o.Metallic と o.Smoothness にはプロパティ変数をそのまま繋いでいます。
インスペクターでぐりぐり調節できますね。(Range なので)
o.Alpha には c のアルファ(テクスチャと色のアルファを掛け合わせた値)をつないでいますが、
今回の例は不透明シェーダーなので何を入れても変化はありません。
ただ、なんとなく気持ち悪い気がするので、私は大抵 o.Alpha = 1 としています。
接続していない項目は自動的にデフォルト値が適用されます。
Fallback
FallBack "すべり止めシェーダー名"
先にも書いたとおり、すべり止めの役割があるので、高機能なシェーダーを指定してはいけません。
一番単純なシェーダーを指定すべきです。
ただし、すべり止め効果以外にも Replaced Shader 云々と色々深い話があり、
正しく設定しないと影が描画されなかったりします。
が、とりあえず難しいことは考えず、以下のようにしておけば概ね問題ないでしょう。
◆ 不透明シェーダーの場合
Fallback "Diffuse"
◆ 透明シェーダーの場合
Fallback "Transparent/Diffuse"
◆ アルファテストシェーダーの場合(葉っぱとか、アルファでクリッピングするやつ)
Fallback "Transparent/Cutout/Diffuse"
おわりに
今回はサーフェースシェーダーの基本的な構造を見てみました。
今後もシェーダーチュートリアルを書いていきますので乞うご期待。
Hey there this is kind of of off topic but I was wanting to know if blogs use WYSIWYG editors or if you have to manually code with HTML.
I’m starting a blog soon but have no coding know-how so I wanted to get advice from someone with experience.
Any help would be enormously appreciated! http://google.com
I like this post, enjoyed this one thanks for putting up. https://www.zotero.org/groups/poetbelt4469
Its like you read my mind! You appear to know a lot about this,
like you wrote the book in it or something. I think that you
can do with a few pics to drive the message home a little bit, but other than that, this
is fantastic blog. A great read. I’ll definitely be back. https://www.dailystrength.org/journals/real-world-secrets-and-techniques-of-instagram-in-the-united-sta
Keep on writing, great job! http://www.seaside-residences.sg/seaside-residecnes-showflat-register-interest-preview
always i used to read smaller content that also clear their motive, and that is also happening
with this paragraph which I am reading here. http://www.seaside-residences.sg/project-details-for-seaside-residences-frasers-centrepoint-homes
I absolutely love your site.. Great colors & theme.
Did you build this website yourself? Please reply back as I’m hoping to create my very
own blog and want to learn where you got this from or
what the theme is called. Thanks! http://seallaw.cn/comment/html/index.php?page=1&id=110071
I every time spent my half an hour to read this webpage’s articles or reviews all the
time along with a mug of coffee. http://itn-horeca.gr/?option=com_k2&view=itemlist&task=user&id=1614042
Hello There. I discovered your blog the use of msn.
That is a very smartly written article. I’ll be sure to
bookmark it and come back to learn extra of your useful information. Thank you for the post.
I’ll certainly comeback. http://eecoslo.org/?option=com_k2&view=itemlist&task=user&id=1342085
Thanks for sharing your thoughts on 積木製作.
Regards http://5280fm.com/index.php/component/k2/itemlist/user/31808
Right away I am going to do my breakfast, after having my breakfast coming over again to read additional news. http://risuki.com/?option=com_k2&view=itemlist&task=user&id=1169612
Nice weblog here! Additionally your site rather a lot up very fast!
What web host are you the usage of? Can I am getting your affiliate
hyperlink on your host? I desire my website loaded up as quickly as yours lol http://buildexpo.ly/?option=com_k2&view=itemlist&task=user&id=36129
[…] 基本とサーフェースシェーダー | Tsumiki Tech Times […]