Help us understand the problem. What is going on with this article?

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

More than 1 year has passed since last update.

はじめに

こんにちは、アドベントカレンダー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変数にセットできれば、異なる挙動をする複数種類のオーディオビジュアライズ系のシェーダーを一括で管理できたりするので、可読性と表現力がグッと伸びそうです。今後の掘り下げに期待ですね。

utvirtual
VRの普及啓蒙と体験創造を理念として、VR作品の制作・展示、勉強会などを行っているインカレサークル
http://utvirtual.tech/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away