こんにちわ、オオバです。

UnityはiOS、Androidといった
複数のプラットフォームに対して同時開発可能です。

シェーダーもそうですよね。

iOS用のシェーダーを書く、Android用のシェーダーを書く
のように個別のシェーダーって書かないですよね。

しかしiOS、Androidで内部構造は違います。
それぞれシェーダーが必要なんです。

なぜUnityは1つのシェーダーで良いのか解説していきます。

1つのシェーダーを各環境に変換している

【超基礎】なぜUnityは1つのシェーダーで複数環境対応できるのか?_0

Unityは1つのシェーダーファイルを
各プラットフォームに合わせて変換
しています。

Unityを使わず、素の状態でシェーダーを書く場合は、
iOS、Android向けとそれぞれシェーダーを書く必要があります。
すごく大変な作業です。

Unityを使うと、ひとつのシェーダーで
複数のプラットフォームに対応できるのです。

とてもスゴイことです!

この記事の内容

ShaderLabはUnityのシェーダー言語

UnityのシェーダーはShaderLabと呼ばれるUnity独自の記法記法です。
📚 参考サイト : ShaderLab 構文 - Unity マニュアル

Unityのシェーダーは全てShaderLabにのっとって書かなければなりません。

GLSL、Cg、HLSLを含んでいる

【超基礎】なぜUnityは1つのシェーダーで複数環境対応できるのか?_1

ShaderLabは既存のシェーダー言語CgHLSL
組み合わせたような言語仕様です。

Cg、HLSLで書いたシェーダー(ShaderLab)は、
OpenGL向けに書きだされる端末の場合、
HLSL2GLSLでコンパイルされます。

ここで言うコンパイルとはShaderLabから
ターゲットとなる環境のシェーダー言語に変換されるという意味です。

ランタイム中のシェーダーコンパイルと誤認するため
本記事では 「変換」 と言い換えます。

変換後のシェーダーの確認方法

【超基礎】なぜUnityは1つのシェーダーで複数環境対応できるのか?_2

各ターゲットに変換された状態も確認できます。
ピクセルを赤く描画する
シンプルなShaderLabを用意しました。

Shader "Simple"  
{
    SubShader  
    {
        Pass  
        {
            CGPROGRAM  
            #pragma vertex vert_img  
            #pragma fragment frag  

            fixed4 frag (v2f_img i) : SV_Target  
            {
                return fixed4(1, 0, 0, 1);  
            }
            ENDCG  
        }
    }
}

シェーダーインスペクタから変換

先のシェーダーをOpenGLES2.0の環境に
変換したシェーダーを確認していきます。

シェーダーファイルを選択して
Inspecterから変換後のシェーダーを確認できます。

【超基礎】なぜUnityは1つのシェーダーで複数環境対応できるのか?_3

するとこうなります。

※読みやすくするために整形しています。
Shader "Simple"  
{
  SubShader  
  {
    Pass  
    {
      GpuProgramID 16286  
      Program "vp"  
      {
        SubProgram "gles "  
        {
"#version 100  

#ifdef VERTEX
attribute vec4 _glesVertex;  
uniform highp mat4 glstate_matrix_mvp;  
void main ()  
{
  gl_Position = (glstate_matrix_mvp * _glesVertex);  
}
#endif

#ifdef FRAGMENT
void main ()  
{
  gl_FragData[0] = vec4(1.0, 1.0, 1.0, 1.0);  
}
#endif
        "  
        }
      }
      Program "fp"  
      {
        SubProgram "gles "  
        {
"// shader disassembly not supported on gles"  
        }
      }
    }
  }
}

変換されたシェーダーを読むと新しい発見あり

【超基礎】なぜUnityは1つのシェーダーで複数環境対応できるのか?_4

変換されたコードを読んでみると面白いです。
基本的にはShaderLabと同じような処理ですが、
ところどころ違いがあります。

ShaderLabのフラグメントシェーダー
fixed4 frag (v2f i) : SV_Target  
{
    return fixed4(1, 0, 0, 1);  
}
GLSLES2.0のフラグメントシェーダー
void main ()  
{
  gl_FragData[0] = vec4(1.0, 0.0, 0.0, 1.0);  
}

このようにGLSLES2.0では、
整数ではなく少数点表記になっています。
ShaderLabの変換がよしなに
各ターゲットに対して変換していることが分かります。

変換済みシェーダーの用途

【超基礎】なぜUnityは1つのシェーダーで複数環境対応できるのか?_5

変換済みのシェーダーを読むことは
ゲーム開発中に発生します。

描画不具合に出会ったとき、
特に実機でテストした場合です。

といった流れです。

描画周りの開発に携わる場合は
知っておくと役立つかも知れません。

まとめ : Unityは1つのシェーダーを複数環境にそれぞれ変換している

【超基礎】なぜUnityは1つのシェーダーで複数環境対応できるのか?_6

Unityのシェーダーが各プラットフォームへ
変換される仕組みについて解説してきました。

Unityを使えば複数のプラットフォームに
1つのシェーダーで対応できます。

これによって何が良いかというと、
ものづくりに集中できるということです。

iOS、Android向けに同じものを提供するために
Unityがなければひとつずつ移植作業をします。

非常に手間がかかることが予想されます。
というのも修正が入るたびに
移植作業が発生するからです。

Unityを使えば1つのソースを変更することで
各プラットフォームを更新できます。

つまり移植作業がないのです。
※厳密にはあります

【超基礎】なぜUnityは1つのシェーダーで複数環境対応できるのか?_7

開発効率を上げるという意味でも
Unityが扱うシェーダー言語ShaderLabを
覚えるメリットは大きいです。

最近はShader Graphという
プログラムを書かなくても
シェーダーを生成する機能も実装されています。

オオバ的には Shader Graph から入ることをオススメします。
シェーダーの流れを視覚的に理解することができるためです。

いっしょにシェーダーを書けるようになって
面白い表現を作っていきましょう。


フォローすると UIデザイナー力の上がるTwitter やってます!
今日から使えるテクニックを発信中。
ぜひフォローしてみてください!
👉フォローはこちら!

最後まで読んでいただきありがとうございました!
すばらしいシェーダーライフをお過ごしください。

期間限定 最大95%オフセール
効率UPメガバンドル開催中!最大95%オフ!!!
期間 : 11月1日午後15時59分まで
オススメ記事