feature image

2021年9月15日 | ブログ記事

ShaderLabを読もう

この記事は2021夏のブログリレー39日目の記事です。

どうも、wataame89です。最近シェーダーをいじり始めたので、ざっくりと読み方を説明したいと思います。にわか知識なので所々間違ってるかもしれませんがご容赦ください。

はじめに

皆さんはシェーダーとは何かご存じでしょうか。シェーダーとは3DモデルなどのCGを描画するために必要なプログラムのことです。ゲームを制作している人であればUnityなどのゲームエンジンでたまに目にすると思います。単にモデルをそのまま描画するというだけでなく、様々な処理を施して不思議なこともできたりするというところがシェーダーの魅力です。高位のシェーダー師の書くシェーダーともなるともはや魔術です。(traPにも高位シェーダー師が在籍しています)

c

そんなシェーダープログラムですが、あまり一般的でない記法が使われていることもあり、読む気が起きない人もいると思います。ゲーム制作でもシェーダーは重要となってくるので若干でも読めると有利な気がします。そこで、今回はUnityで用いられているShaderLabというシェーダーの言語の記法をざっくりと紹介していきたいと思います。

ShaderLabの流れ

ShaderLabには大まかに分けてSurface ShaderVertex/Fragment Shaderという二つの記法があります。しかしながらSurface ShaderはVertex/Fragment Shaderの簡易版のようなものらしいので今回はVertex/Fragment Shaderについて説明します。

ShaderLabでは基本的にVertexシェーダーFragmentシェーダーを連立して記述します。
Vertex(頂点)シェーダーでは3Dモデルの頂点情報と座標情報からカメラから見た頂点位置(視野角なども考慮)を計算し、Fragment(断片)シェーダーではVertexシェーダーから受け取った情報から画面の描画処理を行います。
それ以外の部分にも記法がありますが、shaderの中で大きく変更されるのはこの二つの部分です。
ざっくり図で説明すると以下のようになります。
a

ShaderLabの最小構成

シェーダーの複雑な記法も説明するとかなり長くなってしまうので最小構成のシェーダープログラムを用いてシェーダーの骨格部のみ説明したいと思います。
細かい設定を省くと最小構成のシェーダーは以下のようなプログラムになります。
基本的にはすべてのシェーダーにこれらの項目が含まれているはずです。

Shader "Example"
{
    SubShader
    {      
        Pass
        {
            CGPROGRAM

            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"

            float4 vert (float4 vertex : POSITION) : SV_POSITION
            {
                return UnityObjectToClipPos(vertex);
            }

            fixed4 frag () : SV_Target
            {
                return 1;
            }

            ENDCG
        }
    }
}

このシェーダーに脚注を足していきます。

Shader "Example" //シェーダーである宣言と名前の宣言(マテリアルに設定する時の名前)
{
    SubShader //複数並べるとプラットフォームごとに変更できる枠組
    {      
        Pass //Vertex ShaderとFragment Shaderを内包する一番重要な枠組。1Passでピクセル当たりに1回描画処理ができるので、画像編集ソフトのレイヤーに相当する。(多分)
        {
            CGPROGRAM //CGの宣言

            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc" //この辺はおまじない
            
            float4 vert (float4 vertex : POSITION) : SV_POSITION //Vertex Shader
            {
                return UnityObjectToClipPos(vertex);
            }
            
            fixed4 frag () : SV_Target //Fragment Shader
            {
                return 1;
            }

            ENDCG //CGの終了宣言
        }
    }
}

Vertex Shaderのみ取り出す。

float4 vert (float4 vertex : POSITION) : SV_POSITION
{
    return UnityObjectToClipPos(vertex);
}

まず、float4は変数の型を示している。floatは変数の正確さを示し、4は代入できる値の数を示す(この場合は4個の値を保持できる)。これにより、vert、vertexという変数を定義している。: POSITIONなどはセマンティクスと呼ばれ、変数の用途を指定し、場合によってはUnity側から値が自動的に入力されたり、値を出力したりできる。UnityObjectToClipPos(vertex)はvertexに格納された3Dモデルの頂点座標よりカメラから見た頂点位置を計算し、returnでvertに値を返している。

つまり座標をvertexに入れてUnityObjectToClipPos(vertex)でカメラからの位置に変換した座標をvertに返しています。

Fragment Shaderのみ取り出す。

fixed4 frag () : SV_Target
{
    return 1;
}

こちらではfixed4が変数の型となっているが、正確性以外あまり変わりはない(float4でも一応動く)。:SV_Targetはピクセルの色を出力することを意味するセマンティクスである。return 1で1 = (1,1,1,1)の値を返している。ここで変数の4つの値、(1,1,1,1)はそれぞれ**r(赤)g(緑)b(青)a(透明度)**を示している。

つまり白色をfragに返しているだけです。

実際に出力してみると、
b
このように赤緑青が合成された白色が出力されます。
このシェーダーでは光の情報を計算していないため、正方形の映っている部分がすべて同じ色で塗りつぶされていることがわかります。

このシェーダーが読めれば、あとは個別の記法を調べることで大抵のシェーダーはざっくりと読めると思います。

参考資料

Unityのシェーダーセマンティクスまとめ
https://qiita.com/sune2/items/fa5d50d9ea9bd48761b2
【Unity】【シェーダ】Unityシェーダチートシート
https://light11.hatenadiary.com/entry/2018/05/06/230414

おわりに

シェーダーは仕組みが若干分かりにくいですが、それが理解できれば後は簡単なプログラミング言語の知識で大体読めるようになっています。
雰囲気だけでもシェーダーについて分かってもらえたら嬉しいです。
明日はtarariraさんの記事です。お楽しみに!

wataame89 icon
この記事を書いた人
wataame89

20B材料系。グラフィック班。ネコ科。

この記事をシェア

このエントリーをはてなブックマークに追加
共有

関連する記事

2021年8月12日
CPCTFを支えたWebshell
mazrean icon mazrean
2022年9月26日
競プロしかシラン人間が web アプリ QK Judge を作った話
tqk icon tqk
2022年9月16日
5日でゲームを作った #tararira
Komichi icon Komichi
2023年9月27日
夏のブログリレーは終わらない【駄文】
Komichi icon Komichi
2023年9月13日
ブログリレーを支えるリマインダー
H1rono_K icon H1rono_K
2023年8月21日
名取さなになりたくてOBSと連携する配信画面を作った
d_etteiu8383 icon d_etteiu8383
記事一覧 タグ一覧 Google アナリティクスについて 特定商取引法に基づく表記