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

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

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

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

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

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

📝 目次

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

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

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

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

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

とてもスゴイことです!

ShaderLabはUnityのシェーダー言語

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

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

GLSL、Cg、HLSLを含んでいる

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

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

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

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

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

各ターゲットに変換された状態も確認できます。
ピクセルを赤く描画する
シンプルな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つのシェーダーで複数環境対応できるのか?_110

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

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"  
        }
      }
    }
  }
}

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

変換されたコードを読んでみると面白いです。
基本的には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のシェーダーが各プラットフォームへ
変換される仕組みについて解説してきました。

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

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

iOS、Android向けに同じものを提供するために
Unityがなければ片方から移植作業をします。

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

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

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

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

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

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

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

👉 オススメ記事

2021秋 Asset Refreshセール
100以上のアセットがなんと50%OFF!!オオバもいくつか買いました!
期間 : 10月2日午後3時59分まで