NinaLabo

個人ゲーム開発者の技術メモ

【memo2】はじめてのフラグメントシェーダー(Unity)

【今日のまとめ】Shader1Scene

フラグメントシェーダーには Passブロック が必要

 vert_img は Unityが標準で用意した頂点シェーダーの関数で、フラグメントシェーダーに対して、uv座標が入ったv2f_img型の変数を渡す

 

 

------------------------------------

Unity でゲームは作っていますが、Shader も 画像処理も初心者です。

アウトプットばかりだとそのうち技術についていけなくなるので、毎日1時間程度は自分の知らないことを少しずつインプットしていこうかと思ってます。

タイトルに【memo】とあるものはほぼ自分用の備忘録なので他の記事よりも殴り書きなのはご容赦ください。

------------------------------------

 

今日は昨日の続きからですね。

ninagreen.hatenablog.com

 

板ポリの上に絵を書こうとしている途中でした。

 

ある地点の座標を受け取って、その色を決める関数を作ると、GPUで全ピクセル分実行されて絵になるということらしいです

 

Shader "Custom/Shader1" {

    CGINCLUDE
    #include "UnityCG.cginc"
}

 

ってことでここまでサンプル通りに打ち込んでたら、エラーが・・

 

No ENDCG tag found after CGINCLUDE tag

 

あ、CGINCLUDE は最後に ENDCG がいるんですね。CGINCLUDEって何?とかVisual StudioでCGINCLUDEの部分に色が付かないのは何故?とか気になりますが、さすがに一旦置いておきます。

 

とりあえず写経して、

 

Shader "Custom/Shader1" {

    CGINCLUDE
    #include "UnityCG.cginc"

    float4 frag_test (v2f_img i) : SV_Target
    {
        return float4 (i.uv.x, i.uv.y, 01);
    }
    ENDCG

    SubShader {
        Pass
        {
        CGPROGRAM
        #pragma vertex vert_img
        #pragma fragment frag_test
        ENDCG
        }
    }
}

 昨日作ったMaterial のShaderの箇所から選択(Shader "Custom/Shader1がそのまま反映されるっぽい

f:id:ninagreen:20180911181212p:plain

 

そうするとなんか色が変わってる。

実行時間なくリアルタイムで反映されるのはいいですね。

f:id:ninagreen:20180911181256p:plain

 

調べていくと、どうやらCGINCLUDEは必須ではなさそう。もっと簡潔にこう書ける

Shader "Custom/Shader1" {
    SubShader {
        Pass
        {
        CGPROGRAM
        #include "UnityCG.cginc"
        #pragma vertex vert_img
        #pragma fragment frag_test

            float4 frag_test (v2f_img i) : SV_Target
            {
                return float4 (i.uv.x, i.uv.y, 01);
            }
        ENDCG
        }
    }
}

 ちなみにこれはフラグメントシェーダーなるものらしい。Surfaceシェーダーのほうが入門としてはよかったっぽいけど、と思ったらそうでもない?

Unityにおける Surface Shader と Vertex/Fragment Shader の大まかな使い分けは、ライトの影響を受けるモノには Surface Shader で、受けないモノには Vertex/Fragment Shader です。

が、勘違いしてはいけません。「Surface Shader > Vertex/Fragment Shader」ではなく、むしろシェーダーの基本は Vertex/Fragment の方です。(以降 V/F Shader と書きます)

 

tsumikiseisaku.com

 

とりあえず先に進もう。ちょいちょい出てくるよくわからないコードはおまじないで覚えればいいのかもしれないけど、一応調べてみた。

 

Shader "Custom/Shader1" {   

// シェーダーの名前を定義かな

 

 

    SubShader {

// SubShader シェーダーの1単位っぽい。Unity 公式ページ、意味不明・・

「Unity の各シェーダーはサブシェーダーの一覧から構成されます。Unity がメッシュを描画するとき、使用するシェーダーを見つけ、ユーザーのグラフィックカードで実行する最初のサブシェーダーを選択します。」

// 同一ファイルに複数のシェーダーを書きたい時はこのSubShaderを並列で並べればいいってことかな

 

        Pass
        {

// フラグメントシェーダーだと必ずPassを書かないといけないらしい。Passって何?

// Unity公式は相変わらずよくわからない、もうちょっと初心者にわかりやすく書いてくれればなあ

Pass ブロックはゲームオブジェクトのジオメトリを 1 回レンダリングします。」 

// 取るとエラーになるし、もうここはフラグメントシェーダーのおまじないってことで・・・

 

        CGPROGRAM

// おそらくCGプログラムをこれから書きますよってこと。今まではCGプログラムじゃなかったのか?

 

        #include "UnityCG.cginc"

// Unityが標準で用意しているシェーダープログラムを読み込む、だと思う
 

        #pragma vertex vert_img
        #pragma fragment frag_test 

// 頂点(Vertex)シェーダー に vert_img関数を、Fragmentシェーダー にfrag_test関数を使うと指定しているっぽい

// frag_test は自分でこのあと定義しているけど、vert_img はどっから出てきたかというと、どうやらUnityCG.cginc で定義されている関数っぽい

// ちなみに #pragma (プラグマ)はコンパイラに指示を与えるもので、コンパイルディレクティブっていうらしい

 // vert_img はこの記事の説明がわかりやすい

www.shibuya24.info

 

            float4 frag_test (v2f_img i) : SV_Target
            {
                return float4 (i.uv.x, i.uv.y, 01);
            }

// ここがメインの処理。uvは0〜1の座標が渡されるので、

// 左上が (0, 0, 0, 1)、左下が(0, 1, 0, 1)、右上が(1, 0, 0, 1)、右下が(1, 1, 0, 1)ってことでしょ?あれ?

f:id:ninagreen:20180911190657p:plain

// UVの座標系は原点が左下なのか、つまり左が0、上が1・・だと

// 左上が (0, 1, 0, 1): 緑、左下が(0, 0, 0, 1): 黒、右上が(1, 1, 0, 1): 黄、右下が(1, 0, 0, 1): 赤

// あってる!

        ENDCG
        }
    }
}

// CGPROGRAM の終わりってことだと思われる

 

なんかシェーダーって前提となる知識が多い印象。内輪で盛り上がっているコミュニティに外からよそ者がやってきたけど、会話に入れなくて困ってる、みたいな気分になります(あくまで個人的な感想です・・・)