14
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

UnityにはShaderのグローバル変数が存在する

Last updated at Posted at 2019-12-15

#はじめに
こんにちは、アドベントカレンダー16日目担当の避雷です。急ですがこれを見てください。
https://docs.unity3d.com/ScriptReference/Shader.SetGlobalFloat.html
シェーダーにグローバル変数なんかあるんだ…複数のシェーダーに一括でパラメータを与えられると色々捗りそうですね、ちょっと調べてみましょう。
#Shader.SetXXX
https://docs.unity3d.com/ScriptReference/Shader.html
ここのドキュメントを読んでみます。
image.png
どうやらBuffer,Color,Float,Float配列などをShaderのグローバル変数として代入して利用することが出来るみたいです。
#実装してみる
global変数はC#で設定するようです。試しに適当な値を代入するコードといくつかのシェーダーがあれば動作検証ぐらいは出来そうです。
##C#のコードを用意する

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ShaderGlobalValueSetter : MonoBehaviour
{

    // Update is called once per frame
    void Update()
    {
        Shader.SetGlobalFloat("GlobalVal",Mathf.Sin(Time.time));
    }
}

ScriptReferenceに基づいて適当にSetGlobalFloatしてみました。
第一引数がShader側の変数名、第二引数がその値です。
#Shader側の実装
試しにグローバル変数を使って色を変えるシェーダーを実装してみましょう。

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

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            // make fog work
            #pragma multi_compile_fog

            #include "UnityCG.cginc"

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

            struct v2f
            {
                float2 uv : TEXCOORD0;
                UNITY_FOG_COORDS(1)
                float4 vertex : SV_POSITION;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;
            float GlobalVal;

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

            fixed4 frag (v2f i) : SV_Target
            {
                // sample the texture
                fixed4 col;
                col.xyz = 0.5 + GlobalVal * 0.5;
                col.w = 1.0;
                // apply fog
                UNITY_APPLY_FOG(i.fogCoord, col);
                return col;
            }
            ENDCG
        }
    }
}

折角globalなのでもう一つぐらい用意してみます。

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

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            // make fog work
            #pragma multi_compile_fog

            #include "UnityCG.cginc"

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

            struct v2f
            {
                float2 uv : TEXCOORD0;
                UNITY_FOG_COORDS(1)
                float4 vertex : SV_POSITION;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;
            float GlobalVal;

            v2f vert (appdata v)
            {
                v2f o;
                v.vertex.xyz += GlobalVal * v.normal * 0.1;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                UNITY_TRANSFER_FOG(o,o.vertex);
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                // sample the texture
                fixed4 col = 1.0;
                // apply fog
                UNITY_APPLY_FOG(i.fogCoord, col);
                return col;
            }
            ENDCG
        }
    }
}

適当にSphereにアタッチしてみます。実行結果はこんな感じです。
e9d8d37c893e4fc74f649812594562a5.gif

C#側で送信したFloatの値が同時に反映されていることが確認できると思います。
PlayModeを止めるとそのままの値で静止します。

#所見
なるほど、ShaderのGlobal変数には中々のポテンシャルがありそうです。C#で解析した音声波形データなんかをglobal変数にセットできれば、異なる挙動をする複数種類のオーディオビジュアライズ系のシェーダーを一括で管理できたりするので、可読性と表現力がグッと伸びそうです。今後の掘り下げに期待ですね。

14
8
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
14
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?