夜風のMixedReality

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

多角形の図面を描くShaderを描く

本日はShader学習枠です。

今回はShader表現の一つとしてサーバーグラフィックスでよく見る多角形の模様を作成します。

〇多角形の方程式

n角形の図形の方程式は次のようになります。

f:id:Holomoto-Sumire:20210408211342j:plain

これをShaderLabで記述します。

〇多角形の処理

次の基礎的なスクリプトを作成しました。

Shader "Custom/NewSurfaceShader"
{
   Properties
    {
        _Color ("Color", color) = (1.0, 1.0, 1.0, 1.0)
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
 
        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include <Lighting.cginc>
            #include <UnityShaderUtilities.cginc>

            struct appdata {
                float4 vertex : POSITION;
                float2 uv: TEXCOORD0;
            };
 
            struct v2f {
                float4 pos : SV_POSITION;
                float2 uv :TEXCOORD0;
            };
 
            v2f vert(appdata v) {
                v2f o;
                o.pos = UnityObjectToClipPos(v.vertex);
                o.uv= v.uv;
                return o;
            }
 
            // Color from the property section
            float4 _Color;
 
            float4 frag(v2f i) : SV_Target {

                
                return _Color;
            }
 
            ENDCG
        }
    }
}

このShaderのを加工します。

まずは多角形を描く関数をさくせいします。

  static const float PI = 3.14159265;
            v2f vert(appdata v) {
                v2f o;
                o.pos = UnityObjectToClipPos(v.vertex);
                o.uv= v.uv;
                return o;
            }
               float dPolygon(float2 p, int n, float size){
                float a = atan2(p.x, p.y) + PI;
                float r = 2 * PI / n;
                return cos(floor(.5 + a / r) * r - a) * length(p) - size;
            }

[PI]は円周率を意味します。

次にUVを移動するための関数を作成します。

            float map(float2 uv){
                float2 iPos = floor(uv);
                float2 fPos = frac(uv);

                fPos.x = fPos.x * 1. - .5;
                fPos.y = fPos.y * 1. - .5;

                return dPolygon(fPos * _Pattern, _N, 0) - _Time.x * 3.;
            }

これによって多角形の値を扱うことができるようになりました。

最後にフラグメントシェーダーを編集します。

            float4 frag(v2f i) : SV_Target {
                fixed4 col = _Color*(sin(map(i.uv) * 10) + 1) /1.6;
                
                return col;
            }

uv情報をmapに渡し、UV上で多角形を描きます。

これによって次の様に多角形が広がる演出を行えます。

f:id:Holomoto-Sumire:20210408215816j:plain

〇Shader全文

// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'

Shader "Custom/NewSurfaceShader"
{
   Properties
    {
        _Color ("Color", color) = (1.0, 1.0, 1.0, 1.0)
        _N("n",float)=6
        _Pattern("pattern",float)=1
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
       
        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include <Lighting.cginc>
            #include <UnityShaderUtilities.cginc>

            struct appdata {
                float4 vertex : POSITION;
                float2 uv: TEXCOORD0;
            };
 
            struct v2f {
                float4 pos : SV_POSITION;
                float2 uv :TEXCOORD0;
            };
             static const float PI = 3.14159265;
            v2f vert(appdata v) {
                v2f o;
                o.pos = UnityObjectToClipPos(v.vertex);
                o.uv= v.uv;
                return o;
            }
               float dPolygon(float2 p, int n, float size){
                float a = atan2(p.x, p.y) + PI;
                float r = 2 * PI / n;
                return cos(floor(.5 + a / r) * r - a) * length(p) - size;
            }
            float _Pattern;
            float _N;
            // Color from the property section
            float4 _Color;

                        float map(float2 uv){
                float2 fPos = frac(uv);

                fPos.x = fPos.x * 1. - .5;
                fPos.y = fPos.y * 1. - .5;

                return dPolygon(fPos * _Pattern, _N, 0) - _Time.x * 3.;
            }
            float4 frag(v2f i) : SV_Target {
                fixed4 col = _Color*(sin(map(i.uv) * 10) + 1) /1.6;
                
                return col;
            }
 
            ENDCG
        }
   

    }
}