前置き
このページでは、UnityでShaderとShader Graphを使ってみたい人向けの解説をしています。
世の中のShader解説は、エンジニアによるものがほとんどだと思います。Shaderを作るのは、基本的にエンジニアの仕事なので当然ですが、いずれの解説も説明が深すぎて、数学やCG知識が本当に全くない人を置き去りにしていると感じています。
もちろん、原理原則を理解した上で作ろう、というのは「べき論」で言えばそうなのですが、「個人で楽しくゲーム作ろうよ!」という人にとっては、少々本格的すぎるとも思う訳です。
「猫 or 猿でも分かる〇〇!!」→数分後→「いや、分かんねぇんだわ、わしは猿以下か・・・」
と文系でゲーム制作と全く縁のなかった私は最初、何度もそういう気持ちになりました。
LV100の人間に、LV1の人の気持ちは分からないものです。
とはいえ、個人でゲーム制作をしていて、よりクオリティの高いゲームを作りたいと思ったときに、シェーダーを使えるようになりたい人も多いと考えています。
そこで、エンジニアを目指す勉強のためではなく、「純粋にもっとリッチな表現のゲームを作りたい!」という人向けに、原理原則の解説ではなく、数学知識がなくても理解が出来るよう、平易にわかりやすく、どうしたらやりたいことが実現出来るか、という観点で解説をします。
本職エンジニアが読んだら、SNSで一言いいたくなるような説明箇所は多分にあると思います。
ですが、このサイトでは炎上覚悟で、あえて原理原則・正確さより、実用的・わかり易さを重視した説明にしています。
正確な原理原則をゼロから本格的に学びたい!という方はブラウザバック推奨です。あしからず!
対象としている人
・個人や数人でUnityを使ってゲームを作ったことがある、作っている人
・Shaderについて名前は聞くけど、実際何なのかよく分かっていない人
・2Dゲームを作っている人、作りたい人
※1.Built-Inの場合はパッケージマネージャーからShader Graphをダウンロードしてください
※2.本職で大規模開発をしているガチの人間が読むような記事ではありません。
そもそもShaderを使えると何が出来るの?
こたえ:よりゲームらしい見た目のゲームが作れるようになる
Shader、名前は聞いたことがあっても、実際に学習まで踏み入れた人はゲーム制作上級者になるんじゃないかな、と思います。ですが、Shaderを使えると、表現の幅が一気に広がります。
一度コツ・ポイントさえ理解さえしてしまえば、とても高度な表現でなければ高いアセットに頼らずとも、ある程度自作出来るようになると思います。
この記事が、自分で作ってみたい!と考えている方の手助けになれば、と思います。
まずは、Shaderを使うと、具体的にこんなことが出来るよというご紹介(冒頭に書きましたが2Dメインです)。
Shaderというのは、画面にどのように表現を行うのかを決定するプログラムのことです。
たとえば、先程のキャラクターの元ファイルは以下です。
Shaderを通すことで、ゲーム画面に出力される前に画像(以後、テクスチャと呼びます)に加工処理を行い、テクスチャを動かしたり、特殊な効果を付与することが出来ます。
また、テクスチャを加工するだけでなく、動画編集ソフトで出来るような画面効果を付与することも出来ます。
普段遊んでいるゲームが「ゲームっぽい」と感じるのは、ゲームに仕込まれている多数の演出によるところが大きいです。これらの演出は、アニメーション・画面効果・デザインなどの沢山の要素が複合して出来ており、シェーダーの知識が無いと作れない演出も多数あります。
シェーダーを使えるとより複雑な演出・アニメーションを作れるようになり、より「ゲームらしい」ゲームを作ることにきっと役立つでしょう。
パーティクルの表現がより豊かになる
もう1つ、Shaderを使うと広がる表現を紹介。
Shaderはパーティクル(エフェクト)の表現を上げるのに多用します。
たとえば、こんなエフェクト。
煙のエフェクトは、シェーダーを使うことで、単に透明度を下げてフェードアウトしてくのではなく、煙が徐々に欠けていくような表現をしています。こういった表現はパーティクルだけの操作ではできません。
泡のエフェクトでは、すこし分かりづらいですが、泡自体を揺らす(ディストーション)ことで、よりリアルな泡の表現が出来ます。
このようにShaderを使えると、表現の幅がグッと広がることでしょう!
とりあえずShaderを作ってみる
けど、Shaderって難しいんじゃないの?
ものは試し。色々説明を聞くより、まず1つオリジナルのShaderを作ってみましょう!!
Unityを触ったことがある人なら10分もかからず作成できます、コードは一切書きません。
Unityでは、Shaderをビジュアル的に作成することとが出来るShader Graphという機能が提供されています。
ノードベースで制作過程が分かるため、エンジニア以外でもシェーダーが作れるツールです。
以下の動画でShader Graphについては詳しく紹介されています。ですが、この動画だと少し長いので、この記事はもう少し簡易に、ShaderGraphを使って手軽にオリジナルShaderを作成するためのチュートリアルになります。
今回、キャラクターにモザイクを掛けるオリジナルシェーダーを作成してみます。
こちらのパブリックドメインのイラストを使用しています。
なにはともあれ、まずはShaderGraphです。プロジェクトウィンドウで、ShaderGraphを選択して作成します。
ここでは、「スプライトUnlit」にしておきます。Unlitにするとライティングの影響を受けなくなります。
スプライトLitでも問題ありません。
Shaderの名前はTestMosaicにしました。
次に、このShaderを使うマテリアルを作成します。基本は1シェーダーに対して、Nのマテリアルという関係です。
先ほど作成したShaderGraphを右クリックして、マテリアルを作成しましょう。
では、実際のShaderGraphの作成に入りましょう。
先程作成したShaderGraphをダブルクリックしてください。以下のような画面になったと思います。
まずは難しいことは考えず、以下の指示どおりに作成してみましょう!
プロパティをまず作成します。プロパティは、通常のプログラムでいうところの変数のようなものです。
プロパティの値をインスペクタから変化させることで、パラメータを調整することが出来ます。
まずは、以下の画面(もし表示されていなければ、画面上部のBlackboardというボタンを押してください)をの+ボタンを押します。
Texture2Dを選択。
名前を「MainTex」とします。「MainTex」という名前には意味があるので、名前は変えないでください。
同じ要領で、今度はFloatを作成します。
こちらの名前は「Resolution」とします。モザイクの解像度(粗さ)を指定するのに使います。
Resolutionの初期値は、64くらいにしておきます。Resolutionを選択した状態で、GraphInspectorにある、Defaultに、64をセットします。
つぎに、ShaderGraphのノードを作成します。
適当なスペースで右クリック > Create から、「SampleTexture2D」というノードを選択して作成します。
このノードは、テクスチャ情報を取得(サンプリングといいます)するのに使います。
次に、先程作成した、MainTexをSampleTextureに接続します。
次に、モザイクを掛ける処理を行うノードを追加します。
先ほどと同様の手順で、右クリック > Createから、「UV」、「Posterize」ノードを追加し、「UV」ノードを、Posterizeノードの「In」に接続します。
すると、「Posterize」ノードは、ドット絵のようなマス目状に区切られた見た目になります。
あと少しです!
先ほど作成したプロパティ、「Resolution」をPosterizeのStepsに接続。
SampleTextureのRGBAを、Fragmentの中の「BaseColor」に接続します。
SampleTextureのRGBAのAを、Fragmentの中の「Alpha」に接続します。
最終形はこちら。
左上にあるSaveAssetボタンを押します。
これで一旦Shaderは完成です!これにより、実際どのような変化が起きたか確認してみましょう。
シーン内に適当なスプライトを配置し、先程作成したマテリアルをアタッチしてみます。
モザイクが掛かったような見た目になりました!
また、インスペクタから、先ほど作ったプロパティ「Resolution」の値を変更してみましょう。
Resolutionの値を変えるだけで、モザイクの度合いを変えることが出来ました!
何ドットで分割するか?というのがResolutionというパラメータです。Resolution=8であれば8×8マスに分割されます。
これだけの操作で、オリジナルのシェーダーが作れてしまいました!
このようにTexture情報を取得(サンプリング)して、加工して出力をする、というのが基本的な2D用Shaderの流れになります。
なんとなく、シェーダーを作るイメージが湧きましたか?
様々な効果を組み合わせたり、効果を掛ける範囲を動かしたり、効果を掛ける場所を限定(マスク)することで、より多様な表現を行うことが出来るようになります。
「これが正しい」という明確な答えがないところが、シェーダーの難しいところであり、楽しいところです!
最後の調整は感覚みたいなところもあります。
作成したShaderGraphの解説
これだけだと、ただ指示通り作っただけなので、先ほど追加したノードがどういう役割だったのかを解説します。
まず、UV > Posterize というノードについて。
このUVというノード、Posterizeにつながずに、SampleTexture2Dにそのまま繋いだ場合は、なにも加工されずに表示されます。
UVとは、テクスチャ上のどの部分が、画面上のどの部分に表示されるかを決めるものです。3Dモデルを制作したことがある方にはお馴染みのワードですね。
ShaderGraph上はこんな見た目をしていますが、
実際にはこのように数字を持っています。(簡略化してUV全体を4×4ピクセルとします、実際のUVはこのマスが何百とあるイメージです)
上記の表を見ると、1カッコの中に2つの値が入っていますね。
これは1つのピクセル(正方形の箱)に、2つの値を持っている状態で、「2次元の値を保持している」といいます。
UVノードは、一番左下を(0,0)、一番右上を(1,1)として、数値がグラデーションしていくノードです。
言い方が難しいのですが、これが加工前のUVノードの標準的な数値の持ち方です。
そして、今回はPosterizeという加工を行いました。
Posterizeというノードは、Steps分、数値を段階的に区切る、という処理をしてくれます。
先程のUVを、Steps=2でPosterizeするとどうなるかというと・・・
このように、4×4単位で区切られていたのが、Step数の2×2の単位で区切られ、数値のグラデーションの滑らかさが減りました(=カクカクになった)。
本来、何百というピクセルをもつテクスチャに対して、Posterize化(=カクカク化)したUVをつなぐことで、カクカクした見た目のモザイクおにぎりが誕生した、という訳です。
ドット絵のゲームを作りたいけど、手持ちのアセットはドットじゃない。。。となっても、この処理を行えばある程度のドット表現が可能でしょう。
(もちろんパフォーマンス的負荷が変換分発生するので、最初からドット素材があるに越したことはないです)
ちなみに、UVノード、色がついているのは少し変な感じがしませんか?
これはShaderGraph上、2次元の値はR(Red)とG(Green)の色で表示されているからです。
コンピューターグラフィックでは、RedとGreenとBlueの値の組み合わせで色を作ります。
括弧の左側の数値がRの値、右側の数値がGの値になるので、左から右にかけて赤が強くなり、下から上にかけて緑が強くなるグラデーションの色味になっているわけですね。
ちなみに、各ピクセルが1次元(1つの数字しか持たない)の場合はどうなるでしょう?
Splitというノードを使うことで、2次元の数値の片方だけを取得することが出来るので、確認してみます。
すると・・・
このように白黒のグラデーションになりました。
ShaderGraph上、1次元の値は白黒で、2次元の値は、R(赤)とG(緑)で表現されています。これを知っておくと、ShaderGraphで実装している内容を理解するのにとっても役立つので、ぜひ覚えておいてください!
(超参考:UVノードと同じ配色を作る方法)
Shaderコードでは出来て、Shader Graphでは難しいこと
Shader Graphは非常に強力なツールで、ノーコードでShaderを作成出来るというメリットがありますが、ShaderGraphでシェーダーを作る上で、ニガテなこと・出来ないこともあります。
ニガテ:ループ(for文)や複雑な計算が必要な処理
Shader Graphではループ処理ができません。
以前Unityの方と話した際、Shader Graphは、処理が一方通行という前提で作られている、みたいなことをおっしゃっていたので、Shader Graph上で出来るループ処理は今後も実装される可能性は低いのでしょう(個人の見解です)。
Shaderでループ処理をどんなときに使うの?という例として、ブラー(ぼかし)処理があります。
ブラー処理は、元のテクスチャから「すこーしだけずらしたテクスチャ」と、元のテクスチャの色を混ぜ合わせることで、ぼかしを作ります。
この、「すこーしだけずらしたテクスチャ」の数が多いほど、きれいなブラーをかけることが出来るのですが、Shader Graphでそれを実現しようとすると、for文を書くことが出来ないので・・・
こんな風に、ループ回数分のノードが出来上がってしまうことになります。
この例だとサンプリング数は7ですが、実際きれいなブラーを掛けたい場合、20くらい必要になるケースもあります。
この画像の約3倍のノードと考えると、メンテ性や視認性が悪くなり、作れるには作れるけど・・・みたいになってしまいがちです。
なので、多数のループが必要になるような処理は、Shader Graphではニガテです。同様に、複雑な計算式が必要になるような場合も、ノードが大量になってしまうため、見づらくなりがちです。
ただ、出来ない、ということではありません。
出来ない:Stencilバッファを使う処理
もう1つは、Shader Graphでは出来ない処理です。ですが、これは少し難しめな話なので読み飛ばしてくれて構いません。
カメラの中に収まっているオブジェクトを画面に描画するとき、「手前」と「奥」にあるものが重なっているとします。
本来、重なっている箇所は、手前だけを描画して、奥を描画しない方が、処理の効率は良さそうですよね?
なので、ゲームエンジン側で、通常は奥側と手前オブジェクトが重なっている箇所を描画しない制御がされています。
この重なり合っている箇所、上の赤点線で囲まれた領域を、Stencilバッファといいます。
通常はこれで問題ないのですが、重なって見えなくなっている箇所にも描画をしたい、というケースがあります。
たとえば、建物の裏に潜んでいる敵を表示したい場合などです。
そのようなケースでは、この赤点線領域を、手前のオブジェクトで上書きするだけでなく、奥側のオブジェクトも描画する処理を行う必要があります。
ですが、ShaderGraphには、Stencilバッファにアクセスする方法が無いのです。
もっと本格的に、凝った表現を作りたい!となったときに、Shader Graphだけだと困るかもしれません。
ですが、そこまで凝ったものを作らないのであれば、特に2DであればShader Graphで解決することの方が多いでしょう。いまUnityが絶賛推している「VFX Graph」とも相性が良く、今後も機能拡張していくことも想定されます。
個人や小規模開発において、Shaderコードじゃないと出来ないこと、というケースは、今後減ってくのではないかな、と思います。
さいごに
第1回はここまで!
第2回はこちら
などについて解説していこうと思います。もしこの記事が良いなと思ったらシェアいただけますと幸いです。
それでは、素敵なゲーム制作ライフを!
コメント
コメント一覧 (7件)
[…] この記事は、はじめてのShader・Shader Graph 解説 の2回目の解説になります。1回目はこちらから。 […]
[…] この記事は、はじめてのShader・Shader Graph 解説 の2回目の解説になります。1回目はこちらから。2回目はこちらから。 […]
[…] 【Unity】わかり易さ特化!はじめてのShader・Shader Graph 解説 1 […]
[…] 実際のShaderGraphを使ってどんなものが作れるのかは、以下の記事で紹介しています。はじめてのShader・Shader Graph 解説 その1はじめてのShader・Shader Graph 解説 その2はじめてのShader・Shader Graph 解説 その3 […]
[…] はじめてのShader・Shader Graph 解説 その1はじめてのShader・Shader Graph 解説 その2はじめてのShader・Shader Graph 解説 その3はじめてのShader・Shader Graph 解説 その4 […]
[…] はじめてのShader・Shader Graph 解説 その1はじめてのShader・Shader Graph 解説 その2はじめてのShader・Shader Graph 解説 その3はじめてのShader・Shader Graph 解説 その4はじめてのShader・Shader Graph 解説 その5 […]
[…] はじめてのShader・Shader Graph 解説 その1 :シェーダーってそもそも何?ShaderGrphはなにが出来る?はじめてのShader・Shader Graph 解説 その2:ShaderGrphで学ぶ、CGの色のキホンはじめてのShader・Shader Graph 解説 その3:超汎用・頻出ノードの使い方はじめてのShader・Shader Graph 解説 その4:ShaderGraphの編集画面の見方(解説書)はじめてのShader・Shader Graph 解説 その5:基本のテクスチャを動かすUVスクロールのやり方はじめてのShader・Shader Graph 解説 その6:ノイズの使い方 […]