夜風のMixedReality

xRと出会って変わった人生と出会った技術を書き残すためのGeekなHoloRangerの居場所

Hex表現を使用した出現シェーダーを作る まとめ

本日はUnityShader枠です。

先日までHex表現を行うシェーダーで出現エフェクトを作成しいていました。

今回はまとめ記事になります。

〇Hex.hlsl

今回の出現シェーダーの肝は参考として紹介させていただいているブログ記事様により公開されているShaderGraph用のカスタムノードを参考にHLSL文のみを抽出してHex.hlslとして利用しています。

gist.github.com

ShaderLab内では#include "Hex.hlsl"と宣言することでHexagon()**メソッドを使用できるようになります。

〇六角形上にテクスチャが出現するシェーダー

ベーシックに黒いキューブからパラメータによってテクスチャが現れるシェーダーです。

Shader "Unlit/HexShader"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
        _Scale("Scale" ,float) = 0
        _Power("Power",float) = 0
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100

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

            #include "UnityCG.cginc"
            #include  "Hex.hlsl"

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

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

            sampler2D _MainTex;
            float4 _MainTex_ST;
            float _Scale;
            float _Power;
            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
            {
                float2 Hex;
                float2 HexUV;
                float HexPos;
                float2 HexIndex;
                Hexagon(i.uv,_Scale,HexIndex,HexPos,HexUV ,Hex);
                
                fixed4 col = tex2D(_MainTex, i.uv);
                
                col *=  float4(1,1,1,1)* step(Hex,smoothstep(i.uv.y +_Power,0.8,0)).x;
                
                return col;
            }
            ENDCG
        }
    

〇六角形上にテクスチャが出現するシェーダー(透明度)

AlphaToMask Onを定義し、フラグメントシェーダーで出力するカラーのalphaを0.5以下に指定することで該当のピクセルが破棄され透明になります。

Shader "Unlit/HexShader"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
        _Scale("Scale" ,float) = 0
        _Power("Power",float) = 0
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100
       AlphaToMask On//追加
        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            // make fog work
            #pragma multi_compile_fog

            #include "UnityCG.cginc"
            #include  "Hex.hlsl"

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

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

            sampler2D _MainTex;
            float4 _MainTex_ST;
            float _Scale;
            float _Power;
            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
            {
                float2 Hex;
                float2 HexUV;
                float HexPos;
                float2 HexIndex;
                Hexagon(i.uv, _Scale, HexIndex, HexPos, HexUV, Hex);

                fixed4 col = tex2D(_MainTex, i.uv);

                col.a *= saturate(1 - float4(1, 1, 1, 1) * step(Hex, smoothstep(i.uv.y + _Power, 0.8, 0)).x);

                return col;
            }
            ENDCG
        }

〇発光演出

発光表現は出力される色に加算(足し算)で発光色を行うことで行えます。

Hexagonメソッドでは次画像のようなHexのIDを取得できるためこれを使用して発光表現を追加しています。

Shader "Unlit/HexShader"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
        _Scale("Scale" ,float) = 0
        _Power("Power",float) = 0
        [HDR]_EmissionColor("Emission" ,color) = (1,1,1,1)
    }
    SubShader
    {
        Tags
        {
            "RenderType"="Opaque"
        }
        LOD 100
        AlphaToMask On
        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            // make fog work
            #pragma multi_compile_fog

            #include "UnityCG.cginc"
            #include  "Hex.hlsl"

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

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

            sampler2D _MainTex;
            float4 _MainTex_ST;
            float _Scale;
            float _Power;
            float4 _EmissionColor;
            
            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
            {
                float2 Hex;
                float2 HexUV;
                float HexPos;
                float2 HexIndex;
                Hexagon(i.uv, _Scale, HexIndex, HexPos, HexUV, Hex);

                fixed4 col = tex2D(_MainTex, i.uv);
                float StepHex = step(Hex, smoothstep(i.uv.y + _Power, 0.8, 0));
                col.a *= saturate(1 - float4(1, 1, 1, 1) * StepHex.x);
                float3 emission = _EmissionColor.rgb*smoothstep(i.uv.y + _Power, 0.8, 0);
                emission *= 1-Hex.x;
                col.rgb += emission;
                return col;
            }
            ENDCG
        }
    }
}

〇六角形上にテクスチャが出現するシェーダー(ワールド座標)

ここまではオブジェクトの持つUVを基準にエフェクトをかけていましたが、Unityのワールド座標基準でエフェクトをかけることもできます。

Unityのワールド座標は頂点シェーダーで以下を宣言します。

o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz; //worldPos
Shader "Unlit/HexShader(WorldPosition)"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
        _Scale("Scale" ,float) = 0
        _Power("Power",float) = 0
        [HDR]_EmissionColor("Emission" ,color) = (1,1,1,1)
    }
    SubShader
    {
        Tags
        {
            "RenderType"="Opaque"
        }
        LOD 100
        AlphaToMask On
        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            // make fog work
            #pragma multi_compile_fog

            #include "UnityCG.cginc"
            #include  "Hex.hlsl"

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

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

            sampler2D _MainTex;
            float4 _MainTex_ST;
            float _Scale;
            float _Power;
            float4 _EmissionColor;
            
            v2f vert(appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz; //worldPos
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                return o;
            }

            fixed4 frag(v2f i) : SV_Target
            {
                float2 Hex;
                float2 HexUV;
                float HexPos;
                float2 HexIndex;
                Hexagon(i.uv, _Scale, HexIndex, HexPos, HexUV, Hex);

                fixed4 col = tex2D(_MainTex, i.uv);
                float StepHex = step(Hex, smoothstep( 0.8, 0,i.worldPos.y + _Power));
                
               col*= 1- StepHex;
                float3 emission = _EmissionColor.rgb*smoothstep( 0.8, 0,i.worldPos.y + _Power);
                emission *= 1-Hex.x;
               col.rgb += emission;
                return col;
            }
            ENDCG
        }
    }
}

〇参考

今回の表現のコアとなる処理は以下の記事を参考にさせえていただいています。

r-ngtm.hatenablog.com