Version: 2018.4
言語: 日本語
グラフィックスチュートリアル
シェーダー: 頂点とフラグメントプログラム

シェーダー: ShaderLab と固定関数シェーダー

ここでは、独自のシェーダーを作成する最初のステップを学習します。ゲームの見た目を制御し、グラフィックスのパフォーマンスを最適化するのに役立ちます。

Unity は強力なシェーディングとマテリアルの言語、 ShaderLab を装備しています。 形式的には、CgFX や Direct3D Effects (.FX) 言語に似ていて、マテリアル を表示するために必要なものすべてを表現します。

シェーダーは、Unity の マテリアルインスペクター でアクセスできるプロパティと、さまざまなグラフィックスハードウェア機能を対象とした複数のシェーダー実装 (SubShaders) を記述します。それぞれが、グラフィックスハードウェアの完全な描画状態と使用する頂点/フラグメントプログラムを描画します。シェーダープログラムは高レベルの Cg/HLSL プログラミング言語で書かれています。

ここでは、いわゆる “固定関数” 表記を使用して、とてもシンプルなシェーダーを書く方法を説明します。 シェーダー - 頂点とフラグメントプログラム では、頂点とフラグメント シェーダープログラム を説明します。これらのページは OpenGL や Direct3D のレンダーステートの基本的な知識を持ち、HLSLCgGLSLまたはMetal などのシェーダープログラミング言語に関していくらか知っていることを前提としています。

初めに

シェーダーを新規作成するには、メニューバーから Assets > Create > Shader > Unlit Shader を選択するか、既存のシェーダーをコピーし、そこから作業します。新しいシェーダーは、Project ウィンドウ でそれをダブルクリックすることで編集できます。

Unity には、 非常に単純なシェーダーをいわゆる “固定関数” 表記で作成する方法があります。簡単に説明するために、まず、これから始めましょう。 内部では、シェーダーのインポート時に、固定関数シェーダーは標準の 頂点とフラグメントのプログラム に変換されます。

非常に基本的なシェーダーから始めましょう。

Shader "Tutorial/Basic" {
    Properties {
        _Color ("Main Color", Color) = (1,0.5,0.5,1)
    }
    SubShader {
        Pass {
            Material {
                Diffuse [_Color]
            }
            Lighting On
        }
    }
}

この簡単なシェーダーは、もっとも基本的なシェーダーの 1 つを示しています。これは Main Color という色プロパティを定義し、これにピンク色 (R=100% G=50% B=50% アルファ=100%) のデフォルト値を割り当てます。次に Pass を呼び出してオブジェクトをレンダリングし、このパスで、ディフューズマテリアルコンポーネントをプロパティ _Color に設定し、頂点ごとのライティングをオンにします。

このシェーダーをテストするには、ドロップダウンメニューからシェーダーを選択し (Tutorial->Basic)、そのマテリアルをオブジェクトに割り当てます。マテリアルインスペクターで色を微調整し、変更を確認します。次は、もっと複雑なことに挑戦しましょう。

基本的な頂点ライティング

既存の複雑なシェーダーを開く場合、概要をとらえるには若干難しい場合があります。最初に、ビルトインの VertexLit シェーダーを詳細に見てみましょう。このシェーダーは、固定関数パイプラインを使用して、標準の頂点ごとのライティングを実行します。

Shader "VertexLit" {
    Properties {
        _Color ("Main Color", Color) = (1,1,1,0.5)
        _SpecColor ("Spec Color", Color) = (1,1,1,1)
        _Emission ("Emmisive Color", Color) = (0,0,0,0)
        _Shininess ("Shininess", Range (0.01, 1)) = 0.7
        _MainTex ("Base (RGB)", 2D) = "white" { }
    }

    SubShader {
        Pass {
            Material {
                Diffuse [_Color]
                Ambient [_Color]
                Shininess [_Shininess]
                Specular [_SpecColor]
                Emission [_Emission]
            }
            Lighting On
            SeparateSpecular On
            SetTexture [_MainTex] {
                constantColor [_Color]
                Combine texture * primary DOUBLE, texture * constant
            }
        }
    }
}

すべてのシェーダーは、キーワード Shader で始まり、その後にシェーダーの名前を表す文字列が続きます。これは インスペクター に表示される名前です。このシェーダーのすべてのコードは、その後の波括弧 { } (ブロックと呼ばれます) に入れる必要があります。

  • この名前は短く、説明的である必要があります。これは .shader ファイル名に一致する必要はありません。
  • Unity のサブメニューにシェーダーを置くには、スラッシュを使用します (例えば、 MyShaders/TestMyShaders または MyShaders->Test サブメニュー内で、Test と表示されます)。

シェーダーは、SubShader ブロックを伴う Properties ブロックで構成されます。これらについてはそれぞれ後で説明します。

Properties

シェーダーブロックの最初に、すべてのプロパティを定義できます。これは、マテリアルインスペクター で編集できます。VertexLit の例では、このプロパティは次のように見えます。

プロパティは、Properties ブロック内に 1 行ずつ列挙されます。各プロパティは、内部で使用される名前 (ColorMainTex) で始まります。この後の括弧内には、インスペクターで表示される名前とプロパティのタイプがきます。その後、このプロパティのデフォルト値が記述されます。

タイプのリストは、ShaderLab: Properties にあります。デフォルト値は、プロパティのタイプによって決まります。色の例では、デフォルト値は、4 成分のベクトルになるはずです。

プロパティを定義したので、実際のシェーダーを記述する準備ができました。

シェーダー本体

次に進む前に、シェーダーファイルの基本的な構造を定義しましょう。

グラフィックスハードウェアによって、機能が異なります。例えば、グラフィックスカードによってフラグメントプログラムをサポートしているものとしていないものがあります。パスごとに 4 つのテクスチャを処理するものもあれば、2 つまたは 1 つしか処理しないものもあります。ユーザーの持っているハードウェアが何であろうと最大限に活用できるようにするため、シェーダーは、複数の SubShader (サブシェーダー) を含むことができます。Unity がシェーダーをレンダリングすると、すべてのサブシェーダーに展開し、ハードウェアがサポートする最初のサブシェーダーを使用します。

Shader "Structure Example" {
    Properties { /* ...shader properties... }
    SubShader {
        // ...DX11 / GLES3.1 ハードウェアを必要とするサブシェーダー...
    }
    SubShader {
        // ...見栄えは劣るが、すべてのハードウェアで実行できるサブシェーダー :)
    }
}

このシステムにより、Unity はすべての既存のハードウェアをサポートし、それぞれで最高の質を実現します。しかし、一部のシェーダーは多少長くなります。

各サブシェーダーブロック内で、すべてのパスが共有するレンダリング状態を設定し、レンダリングパス自体を定義します。使用できるコマンドの完全なリストは、ShaderLab: Subshader にあります。

Pass

各サブシェーダーは、Pass (パス) の集合です。各パスに対して、オブジェクトジオメトリが描画されるため、少なくとも 1 つのパスが必要です。下の VertexLit シェーダーには、1 つのパスがあります。

// ...スニペット...
Pass {
    Material {
        Diffuse [_Color]
        Ambient [_Color]
        Shininess [_Shininess]
        Specular [_SpecColor]
        Emission [_Emission]
    }
    Lighting On
    SeparateSpecular On
    SetTexture [_MainTex] {
        constantColor [_Color]
        Combine texture * primary DOUBLE, texture * constant
    }
}
// ...スニペット...

パスで定義されたコマンドはすべて、グラフィックスハードウェアを設定し、特定の方法でジオメトリを描画します。

上記の例では、 Material ブロックは、プロパティ値を固定関数のライティングマテリアル設定に紐づけします。コマンド Lighting On は、標準の頂点ライティングをアクティブにし、 SeparateSpecular On は、スペキュラーハイライトに対して、個々の色の使用を可能にします。

これまで説明したコマンドはすべて、固定関数 OpenGL/Direct3D ハードウェアモデルに対して、直接マッピングしています。詳細は、OpenGL red book を参照してください。

次のコマンド SetTexture は非常に重要です。これらのコマンドは、使用したいテクスチャを定義して、レンダリングでどのようにそれらを混合し、結合し、適用するかを定義します。 SetTexture コマンドの後には、使用したいテクスチャのプロパティ名がきます (ここでは _MainTex)。この後には、テクスチャの適用方法を定義する コンバイナーブロック (combiner block) がきます。ブロック内のコマンドは、画面上でレンダリングされる各ピクセルに対して実行されます。

このブロック内で、constantColor (constant の色) 値、つまり、マテリアルの色である _Color を設定します。この constantColorを以下で使用します。

次のコマンドでは、テクスチャと色値の混合方法を指定します。これを、他の色を持つテクスチャや色とブレンドする方法を指定する Combine コマンドで行います。一般に以下のような感じになります。 Combine ColorPart, AlphaPart

ここでは、 ColorPartAlphaPart が、色 (RGB) とアルファ (A) 成分のブレンドをそれぞれ定義します。 AlphaPart が省略されると、 ColorPart と同じブレンドを使用します。

VertexLit の例、 Combine texture * primary DOUBLE, texture * constant

ここでは、 texture は、現在のテクスチャ (ここでは _MainTex) の色です。これは primary 頂点色で乗算 (*) されます。 primary (主要) 色は、頂点ライティング色で、上の Material の値から計算されます。最後に、結果が 2 で乗算され、ライティング強度を増強します (DOUBLE)。アルファ値 (カンマの後) は、 constant 値で乗算された texture です (上の constantColor で設定)。もう 1 つのよく使用されるコンバイナーモードは previous と呼ばれます (このシェーダーでは使用していません)。これは、前の SetTexture 手順のいずれかの結果であり、複数のテクスチャおよび/または色を結合するのに使用されます。

まとめ

ここで例にした VertexLit シェーダーは標準の頂点ライティングとテクスチャのコンバイナーを設定し、レンダリングされたライティング強度を 2 倍にします。

シェーダーにより多くのパスを入れることができ、これらのパスは次々とレンダリングされます。しかし、現在、すでに必要な効果が得られているため、これは不要です。高度な機能を使用しないため、必要なサブシェーダーは 1 つだけです。このシェーダーは、Unity がサポートしているすべてのグラフィックスカードで機能します。

VertexLit は、考えられる中でもっとも基本的なシェーダーです。ハードウェア固有の操作を使用せず、また ShaderLab や Cg/HLSL が提供する特殊でおしゃれなコマンドも使用しませんでした。

次のページ では、Cg/HLSL 言語を使用したカスタムの頂点やフラグメントプログラムの記述法の説明をします。

グラフィックスチュートリアル
シェーダー: 頂点とフラグメントプログラム