そろそろShaderをやるパート1 Unite 2017の動画を見る(基礎知識~フラグメントシェーダーで色を変える)

4 min読了の目安(約3600字TECH技術記事

そろそろShaderをやります

そろそろShaderをやります。そろそろShaderをやりたいからです。
パート100までダラダラ頑張ります。10年かかってもいいのでやります。
100記事分くらい学べば私レベルの初心者でもまあまあ理解できるかなと思っています。

※初心者がメモレベルで記録するので
 技術記事としてはお力になれないかもしれません。

下準備

いつの間にかShaderのサポートがてんこ盛りになってました。
【参考リンク】:Riderがサポートするシェーダー周りの機能メモ

正直、強力な入力補間機能が無いことを言い訳にしてました。
完ぺきではないようですが、勝手に入力補間もコード整形もやってくれるらしいです。

Unite 2017の動画

会社の強い人に入門動画を教えてもらいました。
少し古い動画ですが、たぶん大丈夫だと思います。

【Unite 2017 Tokyo】シェーダープログラミング入門!カスタムシェーダー、作るで!

こんな人におすすめ
・シェーダーを使用してビジュアル改良方法を学びたいプログラマー
・Unityのグラフィックスの仕組みやカスタムシェーダーで何が達成できるか知りたいアーティスト
・シェーダーの基本構造と使用方法を理解したい学生

受講者が得られる知見
・Unityのグラフィックス・パイプラインの仕組みとUnity シェーダーの基本構造
・カスタムシェーダーの作成方法
・頂点シェーダーとフラグメントシェーダーで使用される基本的な数学的コンセプト

動画内のサンプルコード

今回はフラグメントシェーダーを書き換えて色を変更するところまでやります。

Shaderの定義

A set of instructions that runs on the GPU

GPU上で実行されるインストラクション(プログラム)の集合 と講演では定義していました。

##Vertex Shaders(頂点シェーダー)
頂点の位置を変えたり、頂点に情報を付加したりすることできます。

Input

頂点シェーダーはまずジオメトリから
複数の頂点の情報(座標、法線、色など)を受け取ります。

ジオメトリとは、物質の形状、物質、可視属性、配置を定めたもの。3DCGでは、表示図形の座標計算部分のこと。

【参考リンク】:ジオメトリ

Output

新しい頂点座標、およびそのほかの情報を返します。

Fragment Shaders(ピクセルシェーダー)

ピクセルの色をスクリーンのオブジェクトに介して変えます。

Input

ピクセルとなるフラグメントを受け取ります。

フラグメントは、シェーディングしているピクセルの周りの3つの頂点の寄与から与えられる単純なデータです。

【参考リンク】:3Dグラフィックプログラミングのフラグメントとは何ですか?

Output

ピクセルの色、透明度を返します。

扱う言語

・CG(C for Graphics)
・ShaderLab

C言語に似てるそうです。(C言語知らない)
精度に応じてfloathalffixedを使い分けましょうとのことでした。

扱うデータの大きさ?に応じて数字が後ろに付くそうです。

//カラーを扱いたい RGBA
float4 color = float4(1,1,0,1);
//法線ベクトルを扱いたい
float3 normal = float3(0.2,0.5,0.3);

Shaderサンプル

//Shaderの名前
Shader "UniteAsia/Shader01" 
{
    //サブシェーダー シェーダの中身を書くとこらしい 複数書けるとのこと
    //実行できない場合は最後にFallback "○○" と書いとけば○○で実行される
    SubShader 
    {
        //パス Shader本体を書くとこらしい 複数書ける
	Pass
	{
	    //タグ 透明度とか設定できるらしい
	    Tags { "RenderType"="Opaque" }
		
	    //こっから書きますよ みたいな宣言
	    CGPROGRAM
	    //vertexシェーダーとfragmentシェーダーの関数がどれなのか伝える
	    //実行モードにしなくても定義したらUnityが勝手に呼びだしてくれる
	    #pragma vertex vert //vertという名前の関数がvertexシェーダーです と宣言している ※①
	    #pragma fragment frag //fragという名前の関数がfragmentシェーダーです と宣言している ※②
	    //便利関数詰め合わせセットらしい
            #include "UnityCG.cginc"

	    //v2fという構造体を定義 Vertex to Fragment の略
	    //文字通りvertexシェーダーとfragmentシェーダーの間におけるデータのやりとりで使う
	    //vertexシェーダーの結果をfragmentシェーダーに渡す
	    struct v2f 
	    {
	        //位置情報 ":" 以降の大文字はセマンティクスと言って必要なものだけ受け取るために用意されているらしい
		float4 pos : SV_POSITION;
	    };

	    //①で "これがvertexシェーダーです" と宣言した関数
            v2f vert(appdata_base v) //頂点の情報が引数に渡ってくる
	    {
            	//先ほど宣言した構造体のオブジェクトを作る
		v2f o;
            	//"3Dの世界での座標は2D(スクリーン)においてはこの位置になりますよ" という変換を関数を使って行っている
                o.pos = UnityObjectToClipPos(v.vertex);
            	//変換した座標を返す
                return o;
            }

	    //②で "これがfragmentシェーダーです" と宣言した関数
            half4 frag(v2f i) : COLOR //頂点シェーダからの入力(input)が引数に渡ってくる COLORは今はSV_Targetらしい
	    {
		//色情報を返す R G B A
		return half4(1, 0, 0, 1);
            }
	    //ここで終わりの宣言
	    ENDCG
	}
    }
}

適用したら赤くなりました。

フラグメントシェーダー内で返す色情報を変えると、

  half4 frag(v2f i) : COLOR
  {
      //色情報を返す R G B A
      return half4(1, 1, 0, 1);
  }

色が変わりました。

参考リンク

Unityシェーダプログラム入門 UnlitShaderの要素を全て解説