読者です 読者をやめる 読者になる 読者になる

渋谷ほととぎす通信

完全趣味でやってるUnityメモ。説明できないところを説明できるようにするための個人ブログ。昨日の自分より少しでも大きく慣れるように。。。 ※所属団体とは一切関係がありません

Unityのシェーダをとても分かりやすく自分の言葉で説明してみる


f:id:esakun:20150730215258g:plain

Unityを始めてちょうど2年半経ちました。

数タイトルのスマホゲーム開発をお手伝いさせて頂き、何となくUnityと仲良くなれた気はしています。

しかし、まだまだ奥深いUnity。
特に描画周りのシェーダに関する部分にはずっと二の足を踏んでいる状態です。

自分自身の今後の未来を考えても、シェーダからは逃げられそうにないなと。

目を背けていたとはいえ、全く分からない訳ではなく、ShaderLab、GLSLのソースコードを読めば何となく処理内容を理解できますし、概念は分かっているので簡単なカスタマイズをすることくらいは問題ありません。

ただ「人に説明せよ」と言われた時に果たして正しく教えることが出来るだろうか。。。

全く自信ありませんし、また、パフォーマンスの最適化処理を依頼されても非常に時間がかかりそうです。

そこで2016のゴールデンウィークはシェーダを本気で勉強しようと思い、この記事に至ります。  ※間違っていたら是非コメント下さい

  • 1.そもそも「シェーダとは何なのか」ということに立ち返る
  • 2.Unityにおけるシェーダの処理

これらを順番にまとめていきます。調べていく中で発生した副産物は別途記事にしていく予定です。

1.そもそも「シェーダとは何なのか」ということに立ち返る

シェーダってエフェクトでしょ?みたいな感じで思われてそうな印象がありますが、とりあえずググってみます。

シェーダ(英: shader)とは、3次元コンピュータグラフィックスにおいて、シェーディング(陰影処理)を行うコンピュータプログラムのこと。

Wikipedia:シェーダ

シェーダとは、物体そのものが元々持つ設定

教えてgoo:シェーダとは

レンダリングパイプラインにおいて、頂点単位の処理、ピクセル単位の処理 をカスタマイズするためのプログラムのこと

Slide Share:OpenGL ES2.0 一問一答

などなど。

などなどと書きつつ、あまりシェーダを一言で表現したページは見つかりませんでした。
僕なりに出した答え。

シェーダとは「3Dオブジェクトをディスプレイに映し出すためのプログラム」です。

シェーダってエフェクトでしょ?みたいな感じで思われてそうな印象があります

シェーダでエフェクトを表現することもできますが、シェーダがエフェクトなのではなく、シェーダとはプログラムのことです。

なぜシェーダは「3Dオブジェクトをディスプレイに映し出すためのプログラム」なのか

まずは3Dオブジェクトがディスプレイに映し出されるまでの流れを説明します。

f:id:bao_bao:20160508210300p:plain

  1. 表示したい3Dオブジェクトデータをとある筒に渡す
  2. とある筒からディスプレイに表示される

非常に簡略化するとこのような工程を踏みます。

このとある筒とは何かというと、これがレンダリングパイプラインと呼ばれる、ディスプレイに映し出すまでの流れ作業のような過程のことです。(グラフィックスパイプラインとも言う)

レンダリングパイプラインの中には非常に沢山の処理が含まれており、3Dオブジェクトデータをレンダリングパイプラインに渡すことで、様々な変換作業を経て3D上から2Dのディスプレイに表示されます。

下図のように、シェーダはレンダリングパイプラインの一部に含まれます。

f:id:bao_bao:20160508212120p:plain

また、2種類のシェーダが存在します。*1

f:id:bao_bao:20160508212530p:plain

  • 頂点シェーダ (バーテックスシェーダとも言われる)
  • フラグメントシェーダ (ピクセルシェーダとも言われる)

頂点シェーダはその名も通り、3Dオブジェクトの頂点に関わる処理を行います。 フラグメントシェーダは、ディスプレイの1ピクセル毎に処理するシェーダです。

概念的には受け取った3Dオブジェクトの頂点データを頂点シェーダで座標変換などを行い、その結果をフラグメントシェーダに渡し、各ピクセルの色を決め、ディスプレイに映し出されます。

一昔前まではシェーダを使うことはできませんでした*2。固定機能パイプラインと呼ばれるハードウェア側に定義されたカスタマイズ不可の固定機能を使って描画するという方法がとられていました。

f:id:bao_bao:20160508214206p:plain

現在はというと。

f:id:bao_bao:20160508214746p:plain

図のように頂点シェーダフラグメントシェーダの2箇所をプログラムをすることによりでカスタマイズでき、様々な表現が可能になっています。

よって、シェーダとは「3Dオブジェクトをディスプレイに映し出すためのプログラム」というわけです。

少し長くなりましたが、ここまでがそもそも「シェーダとは何なのか」ということに立ち返るの内容でした。

2.Unityにおけるシェーダの処理

Unityのシェーダは何の言語で書かれているのでしょうか。

答えはShaderLabと呼ばれるUnity独自の記法です。
参考Unity - マニュアル: ShaderLab シンタックス

Unityの全てのシェーダはShaderLabで書かなければなりません。ShaderLabで書かなければコンパイルが失敗します。

GLSL、Cg、HLSLはどこにいったのか?

ShaderLabの言語仕様は、Cg、HLSLを組み合わせたようなものになっています。

Cg,、HLSLで書いたシェーダ(ShaderLab)は、OpenGL向けに書きだされる端末の場合、HLSL2GLSLで変換され、GLSLに書き出される仕組みになっています。 ※Metal環境向けならMetalのシェーダ言語(MSL)に書きだされます

確認方法

変換されたファイルを見ることで確認できます。

おそらくShaderLab界では最小コードだと思われるのシェーダを書いてみます。

このコードをOpenGLES2.0の環境に変換してみます。
Shaderファイルを選択しInspecterで変換後のシェーダを確認できます。

f:id:bao_bao:20160508234656p:plain

するとこうなります。
※見やすくするために整形しています

複数環境選択して、変換後のシェーダを確認すると各環境でどのようなシェーダが使われているか分かります。先のソースコードのように、見慣れたGLSLが記述されているため、OpenGLES2.0環境ではGLSLが使われているということを確認できます。

余談ですが、ShaderファイルのインスペクタにはCompiled Codeとコンパイル済みコードとあります。 ここで言うコンパイルとはShaderLabから各環境への言語の変換処理のことです。バイナリデータになるわけではありません。
変換されたものは、ただのテキストなので最終的なシェーダソースコードを確認できます。

各環境のコードは1ファイル内に#ifdefで切り分けられており、OpenGLES2、Metalなど環境毎で実行時にコンパイル(ここではバイナリへのコンパイル)されて処理されます。

まとめ

前半シェーダのざっくりしたレンダリングパイプラインと歴史について、後半Unity内でのシェーダについて割りとゆるめな内容でまとめてみました。

  • UnityのシェーダはShaderLabという独自言語を使って書く
  • ShaderLabはCg、HLSLを使うことが出来る*3
  • 最終的には各環境に向けたシェーダ言語に変換される
  • 実行時にシェーダはコンパイルされる(実行前ではただの文字列でしか無い)

まだまだShaderを人に説明できるところまではいけていません。
引き続き本ブログではどんな細かいところでも僕が理解できていなかったら調べてそれを調査した記事を書いていこうと思っています。


環境

  • MacOS 10.10.5
  • Unity5.3.4f1

GPU Gems 2 日本語版 ?ハイパフォーマンス グラフィックスとGPGPUのためのプログラミング テクニック?
○分厚いし内容は難しいのですが
Shaderを書く上では読んでおきたい一冊

あわせてどうぞ

www.shibuya24.info

www.shibuya24.info

www.shibuya24.info

*1:簡略化するためにジオメトリシェーダは割愛

*2:ここで言うシェーダはプログラマブルシェーダの事を指します

*3:厳密にはGLSLを直接書くことも出来る