見出し画像

【Unity】ShaderGraphからShaderLabに人力で書き出すワザ

UnityのShaderGraphがビルトインパイプラインに書き出し出来る時代になりましたね。
しかし、VRCなどでは使えない機能なので、備忘録としてShaderGraphで作ったシェーダーをスクリプトに描き起こす方法を記します。


Unityバージョン 2021.1.6f1


使用するシェーダーグラフ

ShaderGraph
Materialを割り当てたオブジェクト

結構不思議なシェーダーである。


頂点シェーダーを書く

Create > Shader > UnlitShader を作ってダブルクリックで開く。

fogは使わないのでコメントと共に消しておく。

Shader "Unlit/Demo"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                float4 vertex : SV_POSITION;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                fixed4 col = tex2D(_MainTex, i.uv);
                return col;
            }
            ENDCG
        }
    }
}
右のマテリアルが現在の状態


頂点シェーダー(バーテックスシェーダー)はこの部分。

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                return o;
            }

これからここを書き換えていきます。

Positionノード

ShaderGraphの頂点シェーダー部分

最初のノードを見ていきます。
Positionノードはコード内にある

o.vertex = UnityObjectToClipPos(v.vertex);

これは同次座標において、オブジェクト空間からカメラのクリップ空間へ点を変換するUnityCG.cginc の頂点変換関数だそうです。(ごめん詳しくは分からない)

ここをいじると頂点が移動するみたいです。

Timeノード

TimeノードはUnityのマニュアルにコードが書いてあります。

https://docs.unity3d.com/ja/Packages/com.unity.shadergraph@10.0/manual/Time-Node.html

生成されるコードの例から、ノードで使っている「Sine Time」の項目を見ます。
今回使いたいコードはこちら。

float Time_SineTime = _SinTime.w;


Vector3ノードのY軸を動かしたいときは「o.vertex.y」と書いてあげます。

Addノードは足し算(+)です。

シェーダーコードに戻ってコード追加します。

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);

				o.vertex.y += -_SinTime.w; // 追加

                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                return o;
            }

数値が逆みたいですが同じように動くようになりました。
ShaderGraphと同じよう動かすためには_SinTime.wにマイナスをかけてあげれば移動距離がちょっと変わりますが大体同じになりました。


フラグメントシェーダーを書く

ShaderGraphのフラグメントシェーダー部分

フラグメントシェーダーはこの部分。

            fixed4 frag (v2f i) : SV_Target
            {
                fixed4 col = tex2D(_MainTex, i.uv);
                return col;
            }

すでにテクスチャを貼るコードが書いてあるので利用しましょう。

Colorノード

ColorノードはBlackBoardに変数を定義しているので、シェーダーコードの上のProperties部分を書き換えてインスペクターから設定できるようにします。

    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
		_Color("MainColor", Color) = (1,1,1,1) // 追加
    }


グローバル変数を宣言する

グローバル変数を宣言しないと使えないので、

        sampler2D _MainTex;
        float4 _MainTex_ST;

この部分に書き足します。

            sampler2D _MainTex;
            float4 _MainTex_ST;
			float4 _Color; // 追加

そしてフラグメントシェーダーの関数colに_Colorを乗算(掛け算)をかけてやります。

            fixed4 frag (v2f i) : SV_Target
            {
                fixed4 col = tex2D(_MainTex, i.uv);
				col *= _Color; // 追加
                return col;
            }


そして保存をするとインスペクターにカラーが現れます。

inspector

ShaderGraphと同じように設定してあげます。

inspector

最終的な結果はこんな感じ。

完成したコード全文

Shader "Unlit/Demo"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
		_Color("MainColor", Color) = (1,1,1,1) // 追加
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                float4 vertex : SV_POSITION;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;
			float4 _Color; // 追加

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);

				o.vertex.y += -_SinTime.w; // 追加

                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                fixed4 col = tex2D(_MainTex, i.uv);
				col *= _Color; // 追加
                return col;
            }
            ENDCG
        }
    }
}

まとめ

短い例でしたが、複雑なShaderGraphでも最初のノードからたどってノードを検索してoやcolに足してあげれば似たような結果が出てきます。
(全く同じ結果にするのは難しいかもしれません。)

参考資料


似たようなことをやっている記事

この記事が気に入ったらサポートをしてみませんか?