【Unity入門】シェーダーを書いてみよう!ShaderLabの簡単な書き方!

みなさんこんにちは!

フリーランスプログラマーのsatoです!

ShaderLabはとは Unity上でシェーダーを記述する言語です。

言語と聞くと、難しそうですが…安心してください!

記述のルールさえ覚えてしまえば、実は非常にシンプルな内容なんです!

言語の書き方自体もC#などと大差ないため、覚えることは非常に少ないです。

ぜひこの記事でその記述のルールを学んでみてください!

それではアジェンダです。

[基本] シェーダーとは?
[基本] まずはシェーダーを用意しよう!
[基本] ShaderLabとは?
[基本] シェーダーを書いてみよう!
[応用] 中身を理解しよう!

今回は実際にUnity上でシェーダーを準備し記述までしていきましょう。

もちろん基礎部分の説明もリンクで用意していますので、基礎に不安がある人はそちらを読んで理解しておきましょう。

それではよろしくお願いいたします。

目次

ShaderLabとは?

ShaderLabを一言でいうと「Unity上でシェーダーを記述する言語」です。

先ほども言ったように、非常にシンプルなルールで成り立っているため、一度覚えてしまえば簡単です!

ぜひ今回で基礎部分を学び終えましょう!

そもそもShaderとは?

Shader(シェーダー)を一言で表すと「描画方法を記述したプログラム」と言えるでしょう。

このプログラムがあるからこそ、画面にオブジェクトが表示されるんです。

逆になければ画面には何も表示されません。

「でもそんなの書いた記憶ないよ!」と思う人も多いでしょう。

しかし実はそれは、デフォルトで選択されている「スタンダートシェーダー」が一般的な描画処理を行ってくれているからなんです。

以下の画像は、いつもの四角いCubeオブジェクトです。

この画面の、Inspectorをよく見てください。

スタンダードシェーダーを選択しているのが確認できると思います。

普段意識していなかったかもしれませんが、シェーダーはいつも使用していた機能なんです!

この辺りは以下の記事で詳細を記述していますので、基礎部分がわからない人はぜひ読んでおきましょう。

シェーダーの仕組み

シェーダーの書き方に入る前に、その仕組みを学ぶ必要があります。

最低限「頂点シェーダー」「フラグメントシェーダー」については理解していないと、シェーダーを書くことは難しいでしょう。

そのためまずは以下の記事で、その仕組みを学んでみてください。

シェーダーのファイルを準備しよう

シェーダーを書くために、まずはシェーダーファイルを用意しましょう。

Shaderファイルを作ってみよう!

作り方は簡単です。

「Projectウィンドウ上で右クリック」→「Shader」→「Unlit Shader」を選択しましょう。

また生成時に付ける名前は、今回は「MyShader」という名称にしておきます。

ちゃんと作れましたね!

Shaderファイルをマテリアルに設定しよう!

あとはそれをマテリアルに設定する必要があります。

Custumの項目に、先ほど作ったシェーダーが自動的に追加されているはずなので、そこから選びましょう。

もしくは、いつものようにアイコンを投げ入れる方法でも反映できます。

Shaderスクリプトを開こう!

ここまでうまくいっていれば、マテリアルのinspectorウィンドウの表記は画像のようなに変わっているはずです。

それが確認できたら、スクリプトを一度開いてみましょうか。

先ほど作ったシェーダーファイルをダブルクリックしてエディタ開きましょう!

無事開ければ、ソースコードが表示されるはずです。

シェーダーを書いてみよう!

ではここからは実際に、シェーダーを記述してみましょう!

まずは一番簡単な処理で実行をしてみましょうか。

現在のシェーダープログラムを一度空っぽに削除して、以下のスクリプトを貼り付けてみてください。

このプログラムはシンプルに、モデルを設定した色で表示するシェーダー処理です。

※ただしMyShaderの部分だけ、自分の命名したファイル名に変更しておいてください。

// シェーダーの情報
Shader "Unlit/MyShader"
{
    // Unity上でやり取りをするプロパティ情報
    // マテリアルのInspectorウィンドウ上に表示され、スクリプト上からも設定できる
    Properties
    {
        _Color ("Main Color", Color) = (1,1,1,1) // Color プロパティー (デフォルトは白)   a____
    }
    // サブシェーダー
    // シェーダーの主な処理はこの中に記述する
    // サブシェーダーは複数書くことも可能が、基本は一つ
    SubShader
    {
        // パス
        // 1つのオブジェクトの1度の描画で行う処理をここに書く
        // これも基本一つだが、複雑な描画をするときは複数書くことも可能
        Pass
        {
            CGPROGRAM   // プログラムを書き始めるという宣言

            // 関数宣言
            #pragma vertex vert    // "vert" 関数を頂点シェーダー使用する宣言
            #pragma fragment frag  // "frag" 関数をフラグメントシェーダーと使用する宣言

            // 変数宣言
            fixed4 _Color; // マテリアルからのカラー   a____

            // 頂点シェーダー
            float4 vert (float4 vertex : POSITION) : SV_POSITION
            {
                return UnityObjectToClipPos(vertex);
            }

            // フラグメントシェーダー
            fixed4 frag () : SV_Target
            {
                return _Color;   a____
            }

            ENDCG   // プログラムを書き終わるという宣言
        }
    }
}

処理を書いて、保存するとモデルにシェーダーが反映されて、画像のように真っ白になるはずです。

そして、以下の画像のようにマテリアルのColorパラメーターを変更することで色が変更できるはずです。

まずは、シェーダーの記述に成功しましたね!

次はこのプログラムの意味を順に見ていきましょう。

シェーダーの基礎の基礎!

非常に長いプログラムだったので、気が引けている人もいるかもしれませんが…

内容はシンプルなので、重要な箇所を一箇所ずつ見ていけば簡単です!

重要な箇所は以下の4箇所です。

・プロパティ情報
・関数宣言
・変数宣言
・頂点シェーダー
・フラグメントシェーダー

一つずつ見ていきます。

プロパティ情報

// Unity上でやり取りをするプロパティ情報
// マテリアルのInspectorウィンドウ上に表示され、スクリプト上からも設定できる
Properties
{
  _Color ("Main Color", Color) = (1,1,1,1) // Color プロパティー (デフォルトは白)   a____
}

この部分へは、Unity側から送ってほしい情報を書くことになります。

ここに書いた内容は「このシェーダーを保持しているマテリアル」の「Inspectorウィンドウ上」に表示されています。

この部分ですね!

確かにUnity上から色パラメーターを送ることが出来ているようです。

より具体的な処理内容は以下の通りです。

_Color ("Main Color", Color) = (1,1,1,1) // Color プロパティー (デフォルトは白)   a____

①第一引数「Main Color」という名称で、
②第二引数「Color型」のデータを取得し、
③のちの変数定義箇所でしている_Color変数へ代入している

取得さえしてしまえば、後はシェーダー内の処理で好きに判定や反映を行えますね!

関数宣言

// 宣言
#pragma vertex vert    // "vert" 関数を頂点シェーダー使用する宣言
#pragma fragment frag  // "frag" 関数をフラグメントシェーダーと使用する宣言

一行目は「頂点(vertex)シェーダーでは、vertという関数を呼び出してね!」という意味で…

二行目は「フラグメント(fragment)シェーダーでは、fragという関数を呼び出してね!」という意味です。

これを定義することにより、各シェーダー処理が実行される時に、自作した「vert」「frag」関数を呼び出してもらえるんですね!

関数宣言

// 変数定義
fixed4 _Color; // マテリアルからのカラー

_Colorという変数を準備しています。

先ほどのプロパティ情報箇所の指定によって、この変数にUnityから取得してきたデータが入ることになったわけです。

頂点シェーダー

// 頂点シェーダー
float4 vert (float4 vertex : POSITION) : SV_POSITION
{
    return UnityObjectToClipPos(vertex);
}

頂点シェーダーは先ほど説明で出てきた、頂点情報を操作するシェーダーです。

フラグメントルシェーダー

// フラグメントシェーダー
fixed4 frag () : SV_Target
{
  return _Color;  a____
}

フラグメントシェーダーは、先ほど説明で出てきたピクセル情報を操作するシェーダーです。

今回覚えておくべきこと

今回はShaderLabでのシェーダーの記述の内容について見てきました。

まずは何が書かれているのかを、把握しておきましょう。

今回見てきた中で、重要な箇所は以下の5箇所です。

プロパティ情報 ・・・ Unityから情報を取得するために定義
関数宣言 ・・・ シェーダー処理で、呼ぶ関数を指定
変数宣言 ・・・ 「Unityからデータをうけとる」などの目的のため、変数を定義
頂点シェーダー ・・・ 頂点シェーダーの処理
フラグメントシェーダー・・・ フラグメントシェーダーの処理

処理内容を簡潔にまとめると以下と言えるでしょう。

①変数宣言・プロパティ情報で、必要な情報を取得し…

②関数宣言で指定した頂点シェーダー・フラグメントシェーダー関数で、実際に行う処理を記述する。

これだけ理解できれば、ネット上に転がっている実例や、Unity公式のサンプルを読み解けると思います。

言語の細かい部分として、型などを勉強しつつ、実装していけそうですね!

まとめ

今回はUnityのShaderの書き方について見てきました。

変数の型の詳細など細かい点までは、まだ見ることが出来ていませんが、大まかな流れは理解してもらえたかと思います。

最後にまとめた内容を、忘れずににShaderを引き続き学んでいきましょう!

この記事を書いた人

学生時代を含めると、かれこれ10年以上プログラマーとして過ごしています。
様々な言語や環境、プロジェクトに関わってきましたので、より実践的な記事をみなさんにお届きるよう情報発信していきます!

目次